6502/vasm/syntax/test/syntax.c

438 lines
8.7 KiB
C

/* syntax.c syntax module for vasm */
/* (c) in 2002 by Volker Barthelmann */
#include "vasm.h"
/* The syntax module parses the input (read_next_line), handles
assembly-directives (section, data-storage etc.) and parses
mnemonics. Assembly instructions are split up in mnemonic name,
qualifiers and operands. new_inst returns a matching instruction,
if one exists.
Routines for creating sections and adding atoms to sections will
be provided by the main module.
*/
char *syntax_copyright="vasm test syntax module (c) 2002 Volker Barthelmann";
hashtable *dirhash;
char commentchar=';';
char *defsectname = NULL;
char *defsecttype = NULL;
char *skip(char *s)
{
while (isspace((unsigned char )*s))
s++;
return s;
}
/* check for end of line, issue error, if not */
void eol(char *s)
{
s = skip(s);
if (!ISEOL(s))
syntax_error(6);
}
char *skip_operand(char *s)
{
int par_cnt=0;
while(1){
if(*s=='(') par_cnt++;
if(*s==')'){
if(par_cnt>0)
par_cnt--;
else
syntax_error(3);
}
if(ISEOL(s)||(*s==','&&par_cnt==0))
break;
s++;
}
if(par_cnt!=0)
syntax_error(4);
return s;
}
static void prident(char *p,int len)
{
int olen=len;
while(len--)
putchar(*p++);
printf("(len=%d)",olen);
}
static void handle_section(char *s)
{
char *name,*attr;
if(*s!='\"'){
name=s;
if(!ISIDSTART(*s)){
syntax_error(10);
return;
}
while(ISIDCHAR(*s))
s++;
name=cnvstr(name,s-name);
s=skip(s);
}else{
s++;
name=s;
while(*s&&*s!='\"')
s++;
name=cnvstr(name,s-name);
s=skip(s+1);
}
if(*s==','){
s=skip(s+1);
attr=s;
if(*s!='\"')
syntax_error(7);
else
s++;
attr=s;
while(*s&&*s!='\"')
s++;
attr=cnvstr(attr,s-attr);
s=skip(s+1);
}else
attr="";
new_section(name,attr,1);
switch_section(name,attr);
eol(s);
}
static char *string(char *s,dblock **result)
{
dblock *db=new_dblock();
taddr size;
char *p,esc;
if(*s!='\"')
ierror(0);
else
s++;
p=s;
size=0;
while(*s&&*s!='\"'){
if(*s=='\\')
s=escape(s,&esc);
else
s++;
size++;
}
db->size=size;
db->data=mymalloc(db->size);
s=p;
p=db->data;
while(*s&&*s!='\"'){
if(*s=='\\')
s=escape(s,p++);
else
*p++=*s++;
}
*result=db;
if(*s=!'\"')
syntax_error(7);
else
s++;
return s;
}
static void handle_data(char *s,int size,int noalign,int zeroterm)
{
expr *tree;
dblock *db;
do{
char *opstart=s;
operand *op;
if(size==8&&*s=='\"'){
s=string(s,&db);
add_atom(0,new_data_atom(db,1));
}else{
op=new_operand();
s=skip_operand(s);
if(!parse_operand(opstart,s-opstart,op,DATA_OPERAND(size))){
syntax_error(8);
}else{
atom *a=new_datadef_atom(size,op);
if(noalign)
a->align=1;
add_atom(0,a);
}
}
s=skip(s);
if(*s==','){
s=skip(s+1);
}else if(*s)
syntax_error(9);
}while(*s);
if(zeroterm){
if(size!=8)
ierror(0);
db=new_dblock();
db->size=1;
db->data=mymalloc(1);
*db->data=0;
add_atom(0,new_data_atom(db,1));
}
eol(s);
}
static void handle_global(char *s)
{
symbol *sym;
char *name;
name=s;
if(!(name=parse_identifier(&s))){
syntax_error(10);
return;
}
sym=new_import(name);
sym->flags|=EXPORT;
myfree(name);
eol(s);
}
static void handle_align(char *s)
{
taddr align=parse_constexpr(&s);
atom *a=new_space_atom(number_expr(0),1,0);
a->align=1<<align;
add_atom(0,a);
eol(s);
}
static void handle_space(char *s)
{
expr *space,*fill=0;
space=parse_expr_tmplab(&s);
s=skip(s);
if(*s==','){
s=skip(s+1);
fill=parse_expr_tmplab(&s);
}
add_atom(0,new_space_atom(space,1,fill));
eol(s);
}
static void handle_8bit(char *s){ handle_data(s,8,0,0); }
static void handle_16bit(char *s){ handle_data(s,16,0,0); }
static void handle_32bit(char *s){ handle_data(s,32,0,0); }
static void handle_16bit_noalign(char *s){ handle_data(s,16,1,0); }
static void handle_32bit_noalign(char *s){ handle_data(s,32,1,0); }
static void handle_string(char *s){ handle_data(s,8,0,1); }
static void handle_texts(char *s){ handle_section(".text,\"acrx4\"");eol(s);}
static void handle_datas(char *s){ handle_section(".data,\"adrw4\"");eol(s);}
static void handle_sdatas(char *s){ handle_section(".sdata,\"adrw4\"");eol(s);}
static void handle_sdata2s(char *s){ handle_section(".sdata2,\"adr4\"");eol(s);}
static void handle_rodatas(char *s){ handle_section(".rodata,\"adr4\"");eol(s);}
static void handle_bsss(char *s){ handle_section(".bss,\"aurw4\"");eol(s);}
static void handle_sbsss(char *s){ handle_section(".bss,\"aurw4\"");eol(s);}
struct {
char *name;
void (*func)(char *);
} directives[]={
"section",handle_section,
"dcb",handle_8bit,
"dc.b",handle_8bit,
"dcw",handle_16bit_noalign,
"dc.w",handle_16bit_noalign,
"dcl",handle_32bit_noalign,
"dc.l",handle_32bit_noalign,
"public",handle_global,
"xdef",handle_global,
"xref",handle_global,
"text",handle_texts,
"cseg",handle_texts,
"data",handle_datas,
"bss",handle_bsss,
"align",handle_align,
"ds.b",handle_space,
};
int dir_cnt=sizeof(directives)/sizeof(directives[0]);
/* Handles assembly directives; returns non-zero if the line
was a directive. */
static int handle_directive(char *line)
{
char *s,*name;
hashdata data;
s=skip(line);
if(!ISIDSTART(*s))
return 0;
name=s;
while(ISIDCHAR(*s))
s++;
if(!find_namelen(dirhash,name,s-name,&data))
return 0;
directives[data.idx].func(skip(s));
return 1;
}
/* Very simple, very incomplete. */
void parse(void)
{
char *s,*line,*inst,*ext[MAX_QUALIFIERS?MAX_QUALIFIERS:1],*op[MAX_OPERANDS];
int inst_len,ext_len[MAX_QUALIFIERS?MAX_QUALIFIERS:1],op_len[MAX_OPERANDS];
int i,ext_cnt,op_cnt,par_cnt;
instruction *ip;
while(line=read_next_line()){
s=line;
if(isalnum((unsigned char)*s)){
/* Handle labels at beginning of line */
char *labname,*equ;
symbol *label;
while(*s&&!isspace((unsigned char)*s)&&*s!=':')
s++;
labname=cnvstr(line,s-line);
s=skip(s+1);
if(!strncmp(s,"equ",3)&&isspace((unsigned char)s[3])){
s=skip(s+3);
label=new_abs(labname,parse_expr(&s));
}else{
label=new_labsym(0,labname);
add_atom(0,new_label_atom(label));
}
free(labname);
}
s=parse_cpu_special(s);
if(handle_directive(s))
continue;
/* skip spaces */
s=skip(s);
if(!*s)
continue;
/* read mnemonic name */
inst=s;
if(!ISIDSTART(*s)){
syntax_error(10);
continue;
}
#if MAX_QUALIFIERS==0
while(*s&&!isspace((unsigned char)*s))
s++;
#else
while(*s&&*s!='.'&&!isspace((unsigned char)*s))
s++;
#endif
inst_len=s-inst;
/* read qualifiers */
ext_cnt=0;
while(*s=='.'&&ext_cnt<MAX_QUALIFIERS){
s++;
ext[ext_cnt]=s;
while(*s&&*s!='.'&&!isspace((unsigned char)*s))
s++;
ext_len[ext_cnt]=s-ext[ext_cnt];
if(ext_len[ext_cnt]<=0)
syntax_error(1);
else
ext_cnt++;
}
if(!isspace((unsigned char)*s)) syntax_error(2);
/* read operands, terminated by comma (unless in parentheses) */
s=skip(s);
op_cnt=0;
while(*s&&op_cnt<MAX_OPERANDS){
op[op_cnt]=s;
s=skip_operand(s);
op_len[op_cnt]=s-op[op_cnt];
if(op_len[op_cnt]<=0)
syntax_error(5);
else
op_cnt++;
s=skip(s);
if(*s!=','){
break;
}else{
s=skip(s+1);
}
}
s=skip(s);
if(*s!=0) syntax_error(6);
ip=new_inst(inst,inst_len,op_cnt,op,op_len);
#if MAX_QUALIFIERS>0
if(ip){
for(i=0;i<ext_cnt;i++)
ip->qualifiers[i]=cnvstr(ext[i],ext_len[i]);
for(;i<MAX_QUALIFIERS;i++)
ip->qualifiers[i]=0;
}
#endif
if(ip){
add_atom(0,new_inst_atom(ip));
}else
;
}
}
char *const_prefix(char *s,int *base)
{
if(isdigit((unsigned char)*s)){
*base=10;
return s;
}
if(*s=='$'){
*base=16;
return s+1;
}
if(*s=='%'){
*base=2;
return s+1;
}
*base=0;
return s;
}
char *const_suffix(char *start,char *end)
{
return end;
}
char *get_local_label(char **start)
{
return NULL;
}
char *parse_macro_arg(struct macro *m,char *s,
struct namelen *param,struct namelen *arg)
{
/* no macro support */
return s;
}
int expand_macro(source *src,char **line,char *d,int dlen)
{
return 0;
}
int init_syntax()
{
size_t i;
hashdata data;
dirhash=new_hashtable(0x200); /*FIXME: */
for(i=0;i<dir_cnt;i++){
data.idx=i;
add_hashentry(dirhash,directives[i].name,data);
}
return 1;
}
int syntax_args(char *p)
{
return 0;
}