1 /* syntax.c  syntax module for vasm */
2 /* (c) in 2002-2018 by Volker Barthelmann and Frank Wille */
3 
4 #include "vasm.h"
5 #include "stabs.h"
6 
7 /* The syntax module parses the input (read_next_line), handles
8    assembly-directives (section, data-storage etc.) and parses
9    mnemonics. Assembly instructions are split up in mnemonic name,
10    qualifiers and operands. new_inst returns a matching instruction,
11    if one exists.
12    Routines for creating sections and adding atoms to sections will
13    be provided by the main module.
14 */
15 
16 char *syntax_copyright="vasm std syntax module 5.1a (c) 2002-2018 Volker Barthelmann";
17 hashtable *dirhash;
18 
19 static char textname[]=".text",textattr[]="acrx";
20 static char dataname[]=".data",dataattr[]="adrw";
21 static char sdataname[]=".sdata",sdataattr[]="adrw";
22 static char sdata2name[]=".sdata2",sdata2attr[]="adr";
23 static char rodataname[]=".rodata",rodataattr[]="adr";
24 static char bssname[]=".bss",bssattr[]="aurw";
25 static char sbssname[]=".sbss",sbssattr[]="aurw";
26 static char tocdname[]=".tocd",tocdattr[]="adrw";
27 
28 #if defined(VASM_CPU_C16X) || defined(VASM_CPU_M68K) || defined(VASM_CPU_650X) || defined(VASM_CPU_ARM) || defined(VASM_CPU_Z80)|| defined(VASM_CPU_6800) || defined(VASM_CPU_JAGRISC) || defined(VASM_CPU_QNICE)
29 char commentchar=';';
30 #else
31 char commentchar='#';
32 #endif
33 char *defsectname = textname;
34 char *defsecttype = "acrwx";
35 
36 static char endmname[] = ".endm";
37 static char reptname[] = ".rept";
38 static char endrname[] = ".endr";
39 static struct namelen dendm_dirlist[] = {
40   { 5,&endmname[0] }, { 0,0 }
41 };
42 static struct namelen drept_dirlist[] = {
43   { 5,&reptname[0] }, { 0,0 }
44 };
45 static struct namelen dendr_dirlist[] = {
46   { 5,&endrname[0] }, { 0,0 }
47 };
48 static struct namelen endm_dirlist[] = {
49   { 4,&endmname[1] }, { 0,0 }
50 };
51 static struct namelen rept_dirlist[] = {
52   { 4,&reptname[1] }, { 0,0 }
53 };
54 static struct namelen endr_dirlist[] = {
55   { 4,&endrname[1] }, { 0,0 }
56 };
57 
58 static int parse_end;
59 static int nodotneeded;
60 static int alloccommon;
61 static int align_data;
62 static int noesc;
63 static taddr sdlimit=-1; /* max size of common data in .sbss section */
64 
65 
skip(char * s)66 char *skip(char *s)
67 {
68   while (isspace((unsigned char )*s))
69     s++;
70   return s;
71 }
72 
73 /* check for end of line, issue error, if not */
eol(char * s)74 void eol(char *s)
75 {
76   s = skip(s);
77   if (!ISEOL(s))
78     syntax_error(6);
79 }
80 
81 #ifdef VASM_CPU_M68K
chkidend(char * start,char * end)82 char *chkidend(char *start,char *end)
83 {
84   if ((end-start)>2 && *(end-2)=='.') {
85     char c = tolower((unsigned char)*(end-1));
86 
87     if (c=='b' || c=='w' || c=='l')
88       return end - 2;  /* .b/.w/.l extension is not part of M68k-identifier */
89   }
90   return end;
91 }
92 #endif
93 
skip_operand(char * s)94 char *skip_operand(char *s)
95 {
96   int par_cnt=0;
97   char c;
98 
99   while(1){
100     c = *s;
101     if(START_PARENTH(c)) par_cnt++;
102     else if(END_PARENTH(c)){
103       if(par_cnt>0)
104         par_cnt--;
105       else
106         syntax_error(3);
107     }else if(c=='\''||c=='\"')
108       s=skip_string(s,c,NULL)-1;
109     else if(ISEOL(s)||(c==','&&par_cnt==0))
110       break;
111     s++;
112   }
113   if(par_cnt!=0)
114     syntax_error(4);
115   return s;
116 }
117 
skip_macroparam(char * s)118 static char *skip_macroparam(char *s)
119 {
120   int par_cnt=0;
121   char c;
122 
123   while(1){
124     c = *s;
125     if(START_PARENTH(c)) par_cnt++;
126     if(END_PARENTH(c)){
127       if(par_cnt>0)
128         par_cnt--;
129       else
130         return s;
131     }
132     if(ISEOL(s)||((c==','||isspace((unsigned char)c))&&par_cnt==0))
133       break;
134     s++;
135   }
136   return s;
137 }
138 
comma_constexpr(char ** s)139 static taddr comma_constexpr(char **s)
140 {
141   *s = skip(*s);
142   if (**s == ',') {
143     *s = skip(*s + 1);
144     return parse_constexpr(s);
145   }
146   general_error(6,',');  /* comma expected */
147   return 0;
148 }
149 
handle_section(char * s)150 static void handle_section(char *s)
151 {
152   char *name,*attr,*new,*p;
153   uint32_t mem=0;
154   section *sec;
155 
156   if(!(name=parse_name(&s))){
157     syntax_error(20);  /* section name */
158     return;
159   }
160   if(*s==','){
161     s=skip(s+1);
162     if(*s!='\"')
163       general_error(6,'\"');  /* quote expected */
164     if(attr=parse_name(&s)){
165       if(*s==','){
166         p=s=skip(s+1);
167         if(*s=='@'||*s=='%'){
168           /* ELF section type "progbits" or "nobits" */
169           s++;
170           if(new=parse_identifier(&s)){
171             if(!strcmp(new,"nobits")){
172               myfree(new);
173               if(strchr(attr,'u')==NULL){
174                 new=mymalloc(strlen(attr)+2);
175                 sprintf(new,"u%s",attr);
176                 myfree(attr);
177                 attr=new;
178               }
179             }else{
180               if(strcmp(new,"progbits"))
181                 syntax_error(14);  /* invalid sectiont type ignored */
182               myfree(new);
183             }
184           }
185         }else{
186           /* optional memory flags (vasm-specific) */
187           mem=parse_constexpr(&s);
188           if(s==p) syntax_error(9);  /* memory flags */
189         }
190       }
191     }else{
192       syntax_error(7);  /* section flags */
193       attr="";
194     }
195   }else{
196     attr="";
197     if(!strcmp(name,textname)) attr=textattr;
198     if(!strcmp(name,dataname)) attr=dataattr;
199     if(!strcmp(name,sdataname)) attr=sdataattr;
200     if(!strcmp(name,sdata2name)) attr=sdata2attr;
201     if(!strcmp(name,rodataname)) attr=rodataattr;
202     if(!strcmp(name,bssname)) attr=bssattr;
203     if(!strcmp(name,sbssname)) attr=sbssattr;
204     if(!strcmp(name,tocdname)) attr=tocdattr;
205   }
206 
207   sec=new_section(name,attr,1);
208   sec->memattr=mem;
209   set_section(sec);
210   eol(s);
211 }
212 
handle_org(char * s)213 static void handle_org(char *s)
214 {
215   if (*s == current_pc_char) {    /*  "* = * + <expr>" reserves bytes */
216     s = skip(s+1);
217     if (*s == '+') {
218       add_atom(0,new_space_atom(parse_expr_tmplab(&s),1,0));
219     }
220     else {
221       syntax_error(18);  /* syntax error */
222       return;
223     }
224   }
225   else if (current_section != NULL) {
226     /* .org inside a section is treated as an offset */
227     add_atom(0,new_roffs_atom(parse_expr_tmplab(&s)));
228   }
229   else
230     set_section(new_org(parse_constexpr(&s)));
231   eol(s);
232 }
233 
handle_file(char * s)234 static void handle_file(char *s)
235 {
236   char *name;
237   if(*s!='\"'){
238     general_error(6,'\"');  /* quote expected */
239     return;
240   }
241   name=++s;
242   while(*s&&*s!='\"')
243     s++;
244   if(*s!='\"')
245     general_error(6,'\"');  /* quote expected */
246   name=cnvstr(name,s-name);
247   setfilename(name);
248   eol(++s);
249 }
250 
oplen(char * e,char * s)251 static int oplen(char *e,char *s)
252 {
253   while(s!=e&&isspace((unsigned char)e[-1]))
254     e--;
255   return e-s;
256 }
257 
handle_data(char * s,int size,int noalign)258 static void handle_data(char *s,int size,int noalign)
259 {
260   for (;;){
261     char *opstart=s;
262     operand *op;
263     dblock *db=NULL;
264 
265     if((OPSZ_BITS(size)==8 || OPSZ_BITS(size)==16) && *s=='\"'){
266       if(db=parse_string(&opstart,*s,OPSZ_BITS(size))){
267         add_atom(0,new_data_atom(db,1));
268         s=opstart;
269       }
270     }
271     if(!db){
272       op=new_operand();
273       s=skip_operand(s);
274       if(parse_operand(opstart,s-opstart,op,DATA_OPERAND(size))) {
275         atom *a;
276 
277         a=new_datadef_atom(OPSZ_BITS(size),op);
278         if(!align_data||noalign)
279           a->align=1;
280         add_atom(0,a);
281       }else
282         syntax_error(8);  /* invalid data operand */
283     }
284 
285     s=skip(s);
286     if(*s==',') {
287       s=skip(s+1);
288     }else if(ISEOL(s)){
289       break;
290     }else{
291       general_error(6,',');  /* comma expected */
292       return;
293     }
294   }
295 
296   eol(s);
297 }
298 
do_equ(char * s,int equiv)299 static void do_equ(char *s,int equiv)
300 {
301   char *labname;
302   symbol *label;
303 
304   if(!(labname=parse_identifier(&s))){
305     syntax_error(10);  /* identifier expected */
306     return;
307   }
308   s=skip(s);
309   if(*s!=',')
310     general_error(6,',');  /* comma expected */
311   else
312     s=skip(s+1);
313   if(equiv) check_symbol(labname);
314   label=new_abs(labname,parse_expr_tmplab(&s));
315   myfree(labname);
316   eol(s);
317 }
318 
handle_set(char * s)319 static void handle_set(char *s)
320 {
321   do_equ(s,0);
322 }
323 
handle_equiv(char * s)324 static void handle_equiv(char *s)
325 {
326   do_equ(s,1);
327 }
328 
do_binding(char * s,int bind)329 static void do_binding(char *s,int bind)
330 {
331   symbol *sym;
332   char *name;
333 
334   while(1){
335     if(!(name=parse_identifier(&s))){
336       syntax_error(10);  /* identifier expected */
337       return;
338     }
339     sym=new_import(name);
340     myfree(name);
341     if(((sym->flags&(EXPORT|WEAK|LOCAL))!=0 &&
342         (sym->flags&(EXPORT|WEAK|LOCAL))!=bind)
343        || ((sym->flags&COMMON) && bind==LOCAL))
344       general_error(62,sym->name,get_bind_name(sym)); /* binding already set */
345     else
346       sym->flags|=bind;
347     s=skip(s);
348     if(*s!=',')
349       break;
350     s=skip(s+1);
351   }
352   eol(s);
353 }
354 
handle_global(char * s)355 static void handle_global(char *s)
356 {
357   do_binding(s,EXPORT);
358 }
359 
handle_weak(char * s)360 static void handle_weak(char *s)
361 {
362   do_binding(s,WEAK);
363 }
364 
handle_local(char * s)365 static void handle_local(char *s)
366 {
367   do_binding(s,LOCAL);
368 }
369 
do_align(taddr align,size_t width,expr * fill,taddr max)370 static void do_align(taddr align,size_t width,expr *fill,taddr max)
371 {
372   atom *a = new_space_atom(number_expr(0),width,fill);
373 
374   a->align = align;
375   a->content.sb->maxalignbytes = max;
376   add_atom(0,a);
377 }
378 
alignment(char * s,int mode,size_t patwidth)379 static void alignment(char *s,int mode,size_t patwidth)
380 {
381   int align,max=0;
382   expr *fill=0;
383 
384   align = parse_constexpr(&s);
385   s = skip(s);
386   if (*s == ',') {
387     s = skip(s+1);
388     if (*s != ',')
389       fill = parse_expr_tmplab(&s);
390     s = skip(s);
391     if (*s == ',') {
392       s = skip(s+1);
393       max = parse_constexpr(&s);
394     }
395   }
396   if (!mode)
397     mode = CPU_DEF_ALIGN;
398   if (mode==2 && align>63)
399     syntax_error(23);  /* alignment too big */
400   do_align(mode==1?align:(1<<align),patwidth,fill,max);
401   eol(s);
402 }
403 
handle_even(char * s)404 static void handle_even(char *s)
405 {
406   do_align(2,1,NULL,0);
407   eol(s);
408 }
409 
handle_align(char * s)410 static void handle_align(char *s)
411 {
412   alignment(s,0,1);
413 }
414 
handle_balign(char * s)415 static void handle_balign(char *s)
416 {
417   alignment(s,1,1);
418 }
419 
handle_balignw(char * s)420 static void handle_balignw(char *s)
421 {
422   alignment(s,1,2);
423 }
424 
handle_balignl(char * s)425 static void handle_balignl(char *s)
426 {
427   alignment(s,1,4);
428 }
429 
handle_p2align(char * s)430 static void handle_p2align(char *s)
431 {
432   alignment(s,2,1);
433 }
434 
handle_p2alignw(char * s)435 static void handle_p2alignw(char *s)
436 {
437   alignment(s,2,2);
438 }
439 
handle_p2alignl(char * s)440 static void handle_p2alignl(char *s)
441 {
442   alignment(s,2,4);
443 }
444 
handle_space(char * s)445 static void handle_space(char *s)
446 {
447   expr *space = parse_expr_tmplab(&s);
448   expr *fill = 0;
449 
450   s = skip(s);
451   if (*s == ',') {
452     s = skip(s+1);
453     fill = parse_expr_tmplab(&s);
454   }
455   add_atom(0,new_space_atom(space,1,fill));
456   eol(s);
457 }
458 
handle_size(char * s)459 static void handle_size(char *s)
460 {
461   char *name;
462   symbol *sym;
463 
464   if(!(name=parse_identifier(&s))){
465     syntax_error(10);  /* identifier expected */
466     return;
467   }
468   sym=new_import(name);
469   myfree(name);
470   s=skip(s);
471   if(*s==',')
472     s=skip(s+1);
473   else
474     general_error(6,',');  /* comma expected */
475   sym->size=parse_expr_tmplab(&s);
476   eol(s);
477 }
478 
handle_type(char * s)479 static void handle_type(char *s)
480 {
481   char *name;
482   symbol *sym;
483 
484   if(!(name=parse_identifier(&s))){
485     syntax_error(10);  /* identifier expected */
486     return;
487   }
488   sym=new_import(name);
489   myfree(name);
490   s=skip(s);
491   if(*s==',')
492     s=skip(s+1);
493   else
494     general_error(6,',');  /* comma expected */
495   if(!strncmp(s,"@object",7)){
496     sym->flags|=TYPE_OBJECT;
497     s=skip(s+7);
498   }else if(!strncmp(s,"@function",9)){
499     sym->flags|=TYPE_FUNCTION;
500     s=skip(s+9);
501   }else
502     sym->flags|=parse_constexpr(&s);
503   eol(s);
504 }
505 
new_bss(char * s,int global)506 static void new_bss(char *s,int global)
507 {
508   char *name;
509   symbol *sym;
510   atom *a;
511   taddr size;
512   section *bss;
513 
514   if(!(name=parse_identifier(&s))){
515     syntax_error(10);  /* identifier expected */
516     return;
517   }
518   size=comma_constexpr(&s);
519   if(size<=sdlimit){
520     if(!(bss=find_section(sbssname,sbssattr)))
521       bss=new_section(sbssname,sbssattr,1);
522   }
523   else{
524     if(!(bss=find_section(bssname,bssattr)))
525       bss=new_section(bssname,bssattr,1);
526   }
527   sym=new_labsym(bss,name);
528   sym->flags|=TYPE_OBJECT;
529   if(global) sym->flags|=EXPORT;
530   sym->size=number_expr(size);
531   myfree(name);
532   s=skip(s);
533   if(*s==','){
534     s=skip(s+1);
535     sym->align=parse_constexpr(&s);
536   }
537   else
538     sym->align=DATA_ALIGN(size*bitsperbyte);
539   a=new_label_atom(sym);
540   if(sym->align)
541     a->align=sym->align;
542   add_atom(bss,a);
543   a=new_space_atom(number_expr(size),1,0);
544   if(sym->align)
545     a->align=sym->align;
546   add_atom(bss,a);
547   eol(s);
548 }
549 
handle_comm(char * s)550 static void handle_comm(char *s)
551 {
552   char *name,*start=s;
553   symbol *sym;
554 
555   if (alloccommon){
556     new_bss(s,1);
557     return;
558   }
559   if(!(name=parse_identifier(&s))){
560     syntax_error(10);  /* identifier expected */
561     return;
562   }
563   if ((sym=find_symbol(name))&&(sym->flags&LOCAL)) {
564     myfree(name);
565     new_bss(start,0);  /* symbol is local, make it .lcomm instead */
566     return;
567   }
568 
569   sym=new_import(name);
570   myfree(name);
571   s=skip(s);
572   if(*s==',')
573     s=skip(s+1);
574   else
575     general_error(6,',');  /* comma expected */
576   if (!(sym->size=parse_expr(&s)))
577     return;
578   simplify_expr(sym->size);
579   if(sym->size->type!=NUM){
580     general_error(30);
581     return;
582   }
583   sym->flags|=COMMON|TYPE_OBJECT;
584   s=skip(s);
585   if(*s==','){
586     s=skip(s+1);
587     sym->align=parse_constexpr(&s);
588   }
589   else
590     sym->align=DATA_ALIGN((int)sym->size->c.val*bitsperbyte);
591   eol(s);
592 }
593 
handle_lcomm(char * s)594 static void handle_lcomm(char *s)
595 {
596   new_bss(s,0);
597 }
598 
read_stabexp(char ** s)599 static expr *read_stabexp(char **s)
600 {
601   *s = skip(*s);
602   if (**s == ',') {
603     *s = skip(*s+1);
604     return parse_expr(s);
605   }
606   general_error(6,',');  /* comma expected */
607   return NULL;
608 }
609 
handle_stabs(char * s)610 static void handle_stabs(char *s)
611 {
612   char *name;
613   size_t len;
614   int t,o,d;
615 
616   if (*s == '\"') {
617     skip_string(s,*s,&len);
618     name = mymalloc(len+1);
619     s = read_string(name,s,*s,8);
620     name[len] = '\0';
621   }
622   else {
623     general_error(6,'\"');  /* quote expected */
624     return;
625   }
626   t = comma_constexpr(&s);
627   o = comma_constexpr(&s);
628   d = comma_constexpr(&s);
629   add_atom(0,new_nlist_atom(name,t,o,d,read_stabexp(&s)));
630   eol(s);
631 }
632 
handle_stabn(char * s)633 static void handle_stabn(char *s)
634 {
635   int t,o,d;
636 
637   t = parse_constexpr(&s);
638   o = comma_constexpr(&s);
639   d = comma_constexpr(&s);
640   add_atom(0,new_nlist_atom(NULL,t,o,d,read_stabexp(&s)));
641   eol(s);
642 }
643 
handle_stabd(char * s)644 static void handle_stabd(char *s)
645 {
646   int t,o,d;
647 
648   t = parse_constexpr(&s);
649   o = comma_constexpr(&s);
650   d = comma_constexpr(&s);
651   add_atom(0,new_nlist_atom(NULL,t,o,d,NULL));
652   eol(s);
653 }
654 
handle_incdir(char * s)655 static void handle_incdir(char *s)
656 {
657   char *name;
658 
659   if (name = parse_name(&s))
660     new_include_path(name);
661   eol(s);
662 }
663 
handle_include(char * s)664 static void handle_include(char *s)
665 {
666   char *name;
667 
668   if (name = parse_name(&s)) {
669     eol(s);
670     include_source(name);
671   }
672 }
673 
handle_incbin(char * s)674 static void handle_incbin(char *s)
675 {
676   char *name;
677 
678   if (name = parse_name(&s)) {
679     eol(s);
680     include_binary_file(name,0,0);
681   }
682 }
683 
handle_rept(char * s)684 static void handle_rept(char *s)
685 {
686   utaddr cnt = parse_constexpr(&s);
687 
688   eol(s);
689   new_repeat(cnt,NULL,NULL,
690              nodotneeded?rept_dirlist:drept_dirlist,
691              nodotneeded?endr_dirlist:dendr_dirlist);
692 }
693 
do_irp(int type,char * s)694 static void do_irp(int type,char *s)
695 {
696   char *name;
697 
698   if(!(name=parse_identifier(&s))){
699     syntax_error(10);  /* identifier expected */
700     return;
701   }
702   s=skip(s);
703   if (*s==',')
704     s=skip(s+1);
705   new_repeat(type,name,mystrdup(s),
706              nodotneeded?rept_dirlist:drept_dirlist,
707              nodotneeded?endr_dirlist:dendr_dirlist);
708 }
709 
handle_irp(char * s)710 static void handle_irp(char *s)
711 {
712   do_irp(REPT_IRP,s);
713 }
714 
handle_irpc(char * s)715 static void handle_irpc(char *s)
716 {
717   do_irp(REPT_IRPC,s);
718 }
719 
handle_endr(char * s)720 static void handle_endr(char *s)
721 {
722   syntax_error(12,endrname,reptname);  /* unexpected endr without rept */
723 }
724 
handle_macro(char * s)725 static void handle_macro(char *s)
726 {
727   char *name;
728 
729   if(name = parse_identifier(&s)){
730     s=skip(s);
731     if(ISEOL(s))
732       s=NULL;
733     new_macro(name,nodotneeded?endm_dirlist:dendm_dirlist,s);
734     myfree(name);
735   }else
736     syntax_error(10);  /* identifier expected */
737 }
738 
handle_endm(char * s)739 static void handle_endm(char *s)
740 {
741   syntax_error(12,endmname,".macro");  /* unexpected endm without macro */
742 }
743 
ifdef(char * s,int b)744 static void ifdef(char *s,int b)
745 {
746   char *name;
747   symbol *sym;
748   int result;
749 
750   if (!(name = parse_symbol(&s))) {
751     syntax_error(10);  /* identifier expected */
752     return;
753   }
754   if (sym = find_symbol(name))
755     result = sym->type != IMPORT;
756   else
757     result = 0;
758   myfree(name);
759   cond_if(result == b);
760   eol(s);
761 }
762 
handle_ifd(char * s)763 static void handle_ifd(char *s)
764 {
765   ifdef(s,1);
766 }
767 
handle_ifnd(char * s)768 static void handle_ifnd(char *s)
769 {
770   ifdef(s,0);
771 }
772 
handle_ifb(char * s)773 static void handle_ifb(char *s)
774 {
775   s = skip(s);
776   cond_if(ISEOL(s));
777 }
778 
handle_ifnb(char * s)779 static void handle_ifnb(char *s)
780 {
781   s = skip(s);
782   cond_if(!ISEOL(s));
783 }
784 
ifexp(char * s,int c)785 static void ifexp(char *s,int c)
786 {
787   expr *condexp = parse_expr_tmplab(&s);
788   taddr val;
789   int b;
790 
791   if (eval_expr(condexp,&val,NULL,0)) {
792     switch (c) {
793       case 0: b = val == 0; break;
794       case 1: b = val != 0; break;
795       case 2: b = val > 0; break;
796       case 3: b = val >= 0; break;
797       case 4: b = val < 0; break;
798       case 5: b = val <= 0; break;
799       default: ierror(0); break;
800     }
801   }
802   else {
803     general_error(30);  /* expression must be constant */
804     b = 0;
805   }
806   cond_if(b);
807   free_expr(condexp);
808   eol(s);
809 }
810 
handle_ifeq(char * s)811 static void handle_ifeq(char *s)
812 {
813   ifexp(s,0);
814 }
815 
handle_ifne(char * s)816 static void handle_ifne(char *s)
817 {
818   ifexp(s,1);
819 }
820 
handle_ifgt(char * s)821 static void handle_ifgt(char *s)
822 {
823   ifexp(s,2);
824 }
825 
handle_ifge(char * s)826 static void handle_ifge(char *s)
827 {
828   ifexp(s,3);
829 }
830 
handle_iflt(char * s)831 static void handle_iflt(char *s)
832 {
833   ifexp(s,4);
834 }
835 
handle_ifle(char * s)836 static void handle_ifle(char *s)
837 {
838   ifexp(s,5);
839 }
840 
handle_else(char * s)841 static void handle_else(char *s)
842 {
843   eol(s);
844   cond_skipelse();
845 }
846 
handle_endif(char * s)847 static void handle_endif(char *s)
848 {
849   eol(s);
850   cond_endif();
851 }
852 
handle_bsss(char * s)853 static void handle_bsss(char *s)
854 {
855   s=skip(s);
856   if(!ISEOL(s)){
857     new_bss(s,0);
858   }else{
859     handle_section(bssname);
860     eol(s);
861   }
862 }
863 
handle_8bit(char * s)864 static void handle_8bit(char *s){ handle_data(s,8,0); }
handle_16bit(char * s)865 static void handle_16bit(char *s){ handle_data(s,16,0); }
handle_32bit(char * s)866 static void handle_32bit(char *s){ handle_data(s,32,0); }
handle_64bit(char * s)867 static void handle_64bit(char *s){ handle_data(s,64,0); }
handle_16bit_noalign(char * s)868 static void handle_16bit_noalign(char *s){ handle_data(s,16,1); }
handle_32bit_noalign(char * s)869 static void handle_32bit_noalign(char *s){ handle_data(s,32,1); }
handle_64bit_noalign(char * s)870 static void handle_64bit_noalign(char *s){ handle_data(s,64,1); }
handle_single(char * s)871 static void handle_single(char *s){ handle_data(s,OPSZ_FLOAT|32,0); }
handle_double(char * s)872 static void handle_double(char *s){ handle_data(s,OPSZ_FLOAT|64,0); }
873 #if VASM_CPU_OIL
handle_string(char * s)874 static void handle_string(char *s){ handle_data(s,8,0); }
875 #else
handle_string(char * s)876 static void handle_string(char *s)
877 {
878   handle_data(s,8,0);
879   add_atom(0,new_space_atom(number_expr(1),1,0));  /* terminating zero */
880 }
881 #endif
handle_texts(char * s)882 static void handle_texts(char *s){ handle_section(textname);eol(s);}
handle_datas(char * s)883 static void handle_datas(char *s){ handle_section(dataname);eol(s);}
handle_sdatas(char * s)884 static void handle_sdatas(char *s){ handle_section(sdataname);eol(s);}
handle_sdata2s(char * s)885 static void handle_sdata2s(char *s){ handle_section(sdata2name);eol(s);}
handle_rodatas(char * s)886 static void handle_rodatas(char *s){ handle_section(rodataname);eol(s);}
handle_sbsss(char * s)887 static void handle_sbsss(char *s){ handle_section(sbssname);eol(s);}
handle_tocds(char * s)888 static void handle_tocds(char *s){ handle_section(tocdname);eol(s);}
889 
handle_abort(char * s)890 static void handle_abort(char *s)
891 {
892   syntax_error(11);
893   parse_end = 1;
894 }
895 
handle_err(char * s)896 static void handle_err(char *s)
897 {
898   add_atom(0,new_assert_atom(NULL,NULL,mystrdup(s)));
899 }
900 
handle_fail(char * s)901 static void handle_fail(char *s)
902 {
903   expr *condexp = parse_expr_tmplab(&s);
904   taddr val;
905 
906   if (eval_expr(condexp,&val,NULL,0)) {
907     if (val >= 500)
908       syntax_error(21,(long long)val);
909     else
910       syntax_error(22,(long long)val);
911   }
912   else
913     general_error(30);  /* expression must be constant */
914   eol(s);
915 }
916 
handle_title(char * s)917 static void handle_title(char *s)
918 {
919   char *t;
920   s=skip(s);
921   if(*s!='\"')
922     general_error(6,'\"');  /* quote expected */
923   else
924     s++;
925   t=s;
926   while(*s&&*s!='\"')
927     s++;
928   set_list_title(t,s-t);
929   if(*s!='\"')
930     general_error(6,'\"');  /* quote expected */
931   else
932     s++;
933   eol(s);
934 }
935 
handle_ident(char * s)936 static void handle_ident(char *s)
937 {
938   char *name;
939 
940   if(name=parse_name(&s))
941     setfilename(name);
942   eol(s);
943 }
944 
handle_list(char * s)945 static void handle_list(char *s)
946 {
947   set_listing(1);
948 }
949 
handle_nolist(char * s)950 static void handle_nolist(char *s)
951 {
952   set_listing(0);
953 }
954 
handle_swbeg(char * s)955 static void handle_swbeg(char *s)
956 {
957   /* gas emits no code here? Ignore...? */
958 }
959 
960 struct {
961   char *name;
962   void (*func)(char *);
963 } directives[]={
964   "org",handle_org,
965   "section",handle_section,
966   "string",handle_string,
967   "byte",handle_8bit,
968   "ascii",handle_8bit,
969   "asciz",handle_string,
970   "short",handle_16bit,
971   "half",handle_16bit,
972   "word",handle_16bit,
973   "int",handle_32bit,
974   "long",handle_32bit,
975   "quad",handle_64bit,
976   "2byte",handle_16bit_noalign,
977   "uahalf",handle_16bit_noalign,
978   "4byte",handle_32bit_noalign,
979   "uaword",handle_16bit_noalign,
980   "ualong",handle_32bit_noalign,
981   "8byte",handle_64bit_noalign,
982   "uaquad",handle_64bit_noalign,
983   "float",handle_single,
984   "single",handle_single,
985   "double",handle_double,
986   "text",handle_texts,
987   "data",handle_datas,
988   "bss",handle_bsss,
989   "rodata",handle_rodatas,
990   "sdata",handle_sdatas,
991   "sdata2",handle_sdata2s,
992   "sbss",handle_sbsss,
993   "tocd",handle_tocds,
994   "equ",handle_set,
995   "set",handle_set,
996   "equiv",handle_equiv,
997   "global",handle_global,
998   "globl",handle_global,
999   "extern",handle_global,
1000   "weak",handle_weak,
1001   "local",handle_local,
1002   "even",handle_even,
1003   "align",handle_align,
1004   "balign",handle_balign,
1005   "balignw",handle_balignw,
1006   "balignl",handle_balignl,
1007   "p2align",handle_p2align,
1008   "p2alignw",handle_p2alignw,
1009   "p2alignl",handle_p2alignl,
1010   "space",handle_space,
1011   "skip",handle_space,
1012   "zero",handle_space,
1013   "comm",handle_comm,
1014   "lcomm",handle_lcomm,
1015   "size",handle_size,
1016   "type",handle_type,
1017   "file",handle_file,
1018   "stabs",handle_stabs,
1019   "stabn",handle_stabn,
1020   "stabd",handle_stabd,
1021   "incdir",handle_incdir,
1022   "include",handle_include,
1023   "incbin",handle_incbin,
1024   "rept",handle_rept,
1025   "irp",handle_irp,
1026   "irpc",handle_irpc,
1027   "endr",handle_endr,
1028   "macro",handle_macro,
1029   "endm",handle_endm,
1030   "ifdef",handle_ifd,
1031   "ifndef",handle_ifnd,
1032   "ifb",handle_ifb,
1033   "ifnb",handle_ifnb,
1034   "if",handle_ifne,
1035   "ifeq",handle_ifeq,
1036   "ifne",handle_ifne,
1037   "ifgt",handle_ifgt,
1038   "ifge",handle_ifge,
1039   "iflt",handle_iflt,
1040   "ifle",handle_ifle,
1041   "else",handle_else,
1042   "endif",handle_endif,
1043   "abort",handle_abort,
1044   "err",handle_err,
1045   "fail",handle_fail,
1046   "title",handle_title,
1047   "ident",handle_ident,
1048   "list",handle_list,
1049   "nolist",handle_nolist,
1050   "swbeg",handle_swbeg,
1051 };
1052 
1053 int dir_cnt=sizeof(directives)/sizeof(directives[0]);
1054 
1055 /* checks for a valid directive, and return index when found, -1 otherwise */
check_directive(char ** line)1056 static int check_directive(char **line)
1057 {
1058   char *s,*name;
1059   hashdata data;
1060 
1061   s = skip(*line);
1062   if (!ISIDSTART(*s))
1063     return -1;
1064   name = s++;
1065   while (ISIDCHAR(*s))
1066     s++;
1067   if (*name == '.')
1068     name++;
1069   else if (!nodotneeded)
1070     return -1;
1071   if (!find_namelen_nc(dirhash,name,s-name,&data))
1072     return -1;
1073   *line = s;
1074   return data.idx;
1075 }
1076 
1077 /* Handles assembly directives; returns non-zero if the line
1078    was a directive. */
handle_directive(char * line)1079 static int handle_directive(char *line)
1080 {
1081   int idx = check_directive(&line);
1082 
1083   if (idx >= 0) {
1084     directives[idx].func(skip(line));
1085     return 1;
1086   }
1087   return 0;
1088 }
1089 
parse(void)1090 void parse(void)
1091 {
1092   char *s,*line,*ext[MAX_QUALIFIERS?MAX_QUALIFIERS:1],*op[MAX_OPERANDS];
1093   char *labname,*start;
1094   int inst_len,ext_len[MAX_QUALIFIERS?MAX_QUALIFIERS:1],op_len[MAX_OPERANDS];
1095   int ext_cnt,op_cnt;
1096   instruction *ip;
1097 
1098   while (line=read_next_line()){
1099     if (parse_end)
1100       continue;
1101 
1102     /* # is always allowed as a comment at the beginning of a line */
1103     s = skip(line);
1104     if (*s == '#')
1105       continue;
1106 
1107     if (!cond_state()) {
1108       /* skip source until ELSE or ENDIF */
1109       int idx;
1110 
1111       s = line;
1112       if (labname = parse_labeldef(&s,1))  /* skip label field */
1113         myfree(labname);
1114       idx = check_directive(&s);
1115       if (idx >= 0) {
1116         if (!strncmp(directives[idx].name,"if",2))
1117           cond_skipif();
1118         else if (directives[idx].func == handle_else)
1119           cond_else();
1120         else if (directives[idx].func == handle_endif)
1121           cond_endif();
1122       }
1123       continue;
1124     }
1125 
1126     s=skip(line);
1127 
1128     if(handle_directive(s))
1129       continue;
1130 
1131     /* skip spaces */
1132     s=skip(s);
1133     if(ISEOL(s))
1134       continue;
1135 
1136     if(labname=parse_labeldef(&s,1)){
1137       /* we have found a valid global or local label */
1138       add_atom(0,new_label_atom(new_labsym(0,labname)));
1139       s=skip(s);
1140       myfree(labname);
1141     }
1142 
1143     if(ISEOL(s))
1144       continue;
1145 
1146     s=skip(parse_cpu_special(s));
1147     if(ISEOL(s))
1148       continue;
1149 
1150     if(handle_directive(s))
1151       continue;
1152 
1153     /* read mnemonic name */
1154     start=s;
1155     ext_cnt=0;
1156     if(!ISIDSTART(*s)){
1157       syntax_error(10);
1158       continue;
1159     }
1160 #if MAX_QUALIFIERS==0
1161     while(*s&&!isspace((unsigned char)*s))
1162       s++;
1163     inst_len=s-start;
1164 #else
1165     s=parse_instruction(s,&inst_len,ext,ext_len,&ext_cnt);
1166 #endif
1167     s=skip(s);
1168 
1169     if(execute_macro(start,inst_len,ext,ext_len,ext_cnt,s))
1170       continue;
1171 
1172     /* read operands, terminated by comma (unless in parentheses)  */
1173     op_cnt=0;
1174     while(!ISEOL(s)&&op_cnt<MAX_OPERANDS){
1175       op[op_cnt]=s;
1176       s=skip_operand(s);
1177       op_len[op_cnt]=oplen(s,op[op_cnt]);
1178 #if !ALLOW_EMPTY_OPS
1179       if(op_len[op_cnt]<=0)
1180         syntax_error(5);
1181       else
1182 #endif
1183         op_cnt++;
1184       s=skip(s);
1185       if(*s!=','){
1186         break;
1187       }else{
1188         s=skip(s+1);
1189       }
1190     }
1191     s=skip(s);
1192     if(!ISEOL(s)) syntax_error(6);
1193     ip=new_inst(start,inst_len,op_cnt,op,op_len);
1194 #if MAX_QUALIFIERS>0
1195     if(ip){
1196       int i;
1197       for(i=0;i<ext_cnt;i++)
1198         ip->qualifiers[i]=cnvstr(ext[i],ext_len[i]);
1199       for(;i<MAX_QUALIFIERS;i++)
1200         ip->qualifiers[i]=0;
1201     }
1202 #endif
1203     if(ip){
1204       add_atom(0,new_inst_atom(ip));
1205     }else
1206       ;
1207   }
1208 
1209   cond_check();
1210 }
1211 
1212 /* get defaults and qualifiers for a macro argument name specifier */
macro_arg_opts(macro * m,int argno,char * name,char * s)1213 char *macro_arg_opts(macro *m,int argno,char *name,char *s)
1214 {
1215   int req = 0;
1216   char *end;
1217   char *new = NULL;
1218 
1219   if (*s==':' && (end=skip_identifier(s+1))!=NULL) {
1220     if (end-s==4 && !strnicmp(s+1,"req",3)) {
1221       /* required argument: argname:req */
1222       req = 1;
1223       new = s = skip(s+4);
1224     }
1225     else if (end-s==7 && !strnicmp(s+1,"vararg",6)) {
1226       /* define vararg position: argname:vararg */
1227       m->vararg = argno;
1228       new = s = skip(s+7);
1229     }
1230   }
1231   if (*s == '=') {
1232     /* define a default value for this argument */
1233     s = skip(s+1);
1234     if (end = skip_operand(s)) {
1235       if (req)
1236         syntax_error(13,name);  /* pointless default value for req. parameter */
1237       addmacarg(&m->defaults,s,end);
1238       return end;
1239     }
1240   }
1241   if (new) {
1242     if (req)
1243       addmacarg(&m->defaults,NULL,NULL);  /* mark as required - no default! */
1244     else
1245       addmacarg(&m->defaults,new,new);  /* empty string as default */
1246   }
1247   return new;  /* NULL means: set an empty string as default value */
1248 }
1249 
1250 /* parse next macro argument */
parse_macro_arg(struct macro * m,char * s,struct namelen * param,struct namelen * arg)1251 char *parse_macro_arg(struct macro *m,char *s,
1252                       struct namelen *param,struct namelen *arg)
1253 {
1254   char *idend = skip_identifier(s);
1255 
1256   arg->len = 0;
1257   if (idend!=NULL && idend-s>0) {
1258     char *end = skip(idend);
1259 
1260     if (*end++ == '=') {
1261       /* argument selected by keyword */
1262       arg->name = s;
1263       arg->len = idend - s;
1264       s = skip(end);
1265     }
1266   }
1267 
1268   if (*s == '\'') {
1269     /* evaluate character constant */
1270     unsigned long cc = parse_constexpr(&s);
1271     char buf[16],*ccstr;
1272     int len;
1273 
1274     if ((len = sprintf(buf,"%lu",cc)) < 0)
1275       ierror(0);
1276     ccstr = mystrdup(buf);
1277     param->name = ccstr;
1278     param->len = len;
1279   }
1280   else if (*s == '\"') {
1281     /* pass everything enclosed in quotes, but without the quotes */
1282     param->name = ++s;
1283     while (*s!='\0' && *s!='\"') s++;
1284     param->len = s - param->name;
1285     if (*s == '\"')
1286       s++;
1287     else
1288       general_error(6,'\"');  /* " expected */
1289   }
1290   else {
1291     param->name = s;
1292     s = skip_macroparam(s);
1293     param->len = s - param->name;
1294   }
1295   return s;
1296 }
1297 
1298 /* expands arguments and special escape codes into macro context */
expand_macro(source * src,char ** line,char * d,int dlen)1299 int expand_macro(source *src,char **line,char *d,int dlen)
1300 {
1301   int n,nc=0;
1302   char *end,*s=*line;
1303 
1304   if (*s++ == '\\') {
1305     /* possible macro expansion detected */
1306     if (*s == '@') {
1307       /* \@: insert a unique id */
1308       nc = sprintf(d,"%lu",src->id);
1309       if (nc >= dlen)
1310         nc = -1;
1311     }
1312     else if (*s=='(' && *(s+1)==')') {
1313       /* \() is just skipped, useful to terminate named macro parameters */
1314       nc = 0;
1315       s += 2;
1316     }
1317     else if ((end = skip_identifier(s)) != NULL) {
1318       if ((n = find_macarg_name(src,s,end-s)) >= 0) {
1319         /* \argname: insert named macro parameter n */
1320         nc = copy_macro_param(src,n,d,dlen);
1321         s = end;
1322       }
1323     }
1324     if (nc >= 0)
1325       *line = s;  /* update line pointer when expansion took place */
1326   }
1327   return nc;  /* number of chars written to line buffer, -1: out of space */
1328 }
1329 
my_exec_macro(source * src)1330 void my_exec_macro(source *src)
1331 {
1332 #if 0 /* make it possible to use default values, when params are missing */
1333   if (src->macro->num_argnames>=0 && src->num_params<src->macro->num_argnames)
1334     general_error(24);  /* missing macro parameters (named) */
1335 #endif
1336 }
1337 
const_prefix(char * s,int * base)1338 char *const_prefix(char *s,int *base)
1339 {
1340   if(!isdigit((unsigned char)*s)){
1341     *base=0;
1342     return s;
1343   }
1344   if(*s=='0'){
1345     if(s[1]=='x'||s[1]=='X'){
1346       *base=16;
1347       return s+2;
1348     }
1349     if(s[1]=='b'||s[1]=='B'){
1350       *base=2;
1351       return s+2;
1352     }
1353     if(isdigit((unsigned char)s[1])){
1354       *base=8;
1355       return s;
1356     }
1357     if(s[1]=='d'||s[1]=='D'||s[1]=='f'||s[1]=='F'||s[1]=='r'||s[1]=='R')
1358       s+=2;  /* floating point is handled automatically, so skip prefix */
1359   }
1360   *base=10;
1361   return s;
1362 }
1363 
const_suffix(char * start,char * end)1364 char *const_suffix(char *start,char *end)
1365 {
1366   return end;
1367 }
1368 
get_local_label(char ** start)1369 char *get_local_label(char **start)
1370 /* local labels start with a '.' or end with '$': "1234$", ".1" */
1371 {
1372   char *s = *start;
1373   char *name = NULL;
1374 
1375   if (*s == '.') {
1376     s++;
1377     while (isdigit((unsigned char)*s) || *s=='_')  /* '_' needed for ".\@" */
1378       s++;
1379     if (s > (*start+1)) {
1380       name = make_local_label(NULL,0,*start,s-*start);
1381       *start = skip(s);
1382     }
1383   }
1384   else if (isdigit((unsigned char)*s) || *s=='_') {  /* '_' needed for "\@$" */
1385     s++;
1386     while (isdigit((unsigned char)*s))
1387       s++;
1388     if (*s=='$' && isdigit((unsigned char)*(s-1))) {
1389       s++;
1390       name = make_local_label(NULL,0,*start,s-*start);
1391       *start = skip(s);
1392     }
1393   }
1394   return name;
1395 }
1396 
init_syntax()1397 int init_syntax()
1398 {
1399   size_t i;
1400   hashdata data;
1401   dirhash=new_hashtable(0x200); /*FIXME: */
1402   for(i=0;i<dir_cnt;i++){
1403     data.idx=i;
1404     add_hashentry(dirhash,directives[i].name,data);
1405   }
1406 
1407   cond_init();
1408 #if defined(VASM_CPU_X86)
1409   current_pc_char = '.';
1410 #endif
1411   esc_sequences = !noesc;
1412   nocase_macros = 1;
1413   return 1;
1414 }
1415 
syntax_args(char * p)1416 int syntax_args(char *p)
1417 {
1418   int i;
1419 
1420   if (!strcmp(p,"-align")) {
1421     align_data = 1;
1422     return 1;
1423   }
1424   else if (!strcmp(p,"-nodotneeded")) {
1425     nodotneeded = 1;
1426     return 1;
1427   }
1428   else if (!strcmp(p,"-noesc")) {
1429     noesc = 1;
1430     return 1;
1431   }
1432   else if (!strcmp(p,"-ac")) {
1433     alloccommon = 1;
1434     return 1;
1435   }
1436   else if (!strncmp(p,"-sdlimit=",9)) {
1437     i = atoi(p+9);
1438     sdlimit = (i<=0) ? -1 : i;
1439     return 1;
1440   }
1441 
1442   return 0;
1443 }
1444