mirror of
				https://github.com/alsa-project/alsa-tools.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			463 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			463 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/***************************************************************************
 | 
						|
                          parse.c  -  parses each line, stores in temp space
 | 
						|
                             -------------------
 | 
						|
    Date                 : May 23 2000
 | 
						|
    Copyright            : (C) 2000 by Daniel Bertrand
 | 
						|
    Email                : d.bertrand@ieee.ca
 | 
						|
 ***************************************************************************/
 | 
						|
 | 
						|
/***************************************************************************
 | 
						|
 *                                                                         *
 | 
						|
 *   This program is free software; you can redistribute it and/or modify  *
 | 
						|
 *   it under the terms of the GNU General Public License as published by  *
 | 
						|
 *   the Free Software Foundation; either version 2 of the License, or     *
 | 
						|
 *   (at your option) any later version.                                   *
 | 
						|
 *                                                                         *
 | 
						|
 ***************************************************************************/
 | 
						|
 | 
						|
#include<string.h>
 | 
						|
#include<stdio.h>
 | 
						|
#include"types.h"
 | 
						|
#include"parse.h"
 | 
						|
#include"proto.h" 
 | 
						|
 | 
						|
/*
 | 
						|
This function parses the asm file calling appropriate functions to blow up macros, include files,
 | 
						|
define constants, keep track of equates, and handling assembler directives.
 | 
						|
 | 
						|
This function is called on a line by line basis.
 | 
						|
 | 
						|
normally returns value 0 except when "end" directive is encountered in which case it returns 1,
 | 
						|
 the "endm" directive which return -1, or the "endfor" deirective which returns -2
 | 
						|
*/
 | 
						|
 | 
						|
extern char type_strings[GPR_TYPE_EQUATE+1][20];
 | 
						|
extern int dbg_opt;
 | 
						|
extern char *listing,listtemp[60];
 | 
						|
extern FILE *listfile;
 | 
						|
 | 
						|
int parse( char line_string[MAX_LINE_LENGTH], char *line)
 | 
						|
{
 | 
						|
        int tmp,i,arg[4];
 | 
						|
        static int defmacro=0; //set to 0 unless we're in a macro definition
 | 
						|
        int op_num;
 | 
						|
	char  *leading_symbol=NULL, *op_name_ptr,*tmpc;
 | 
						|
        extern char patch_name[PATCH_NAME_SIZE];
 | 
						|
	extern int ds_addr,ip,tram_addr,tram_delay_count,tram_table_count;
 | 
						|
        extern unsigned int macro_depth;
 | 
						|
     
 | 
						|
        struct sym *sym;
 | 
						|
        struct control *control;
 | 
						|
        
 | 
						|
        extern struct delay tram_delay[MAX_TANK_ADDR];
 | 
						|
        extern struct lookup tram_lookup[MAX_TANK_ADDR];
 | 
						|
	
 | 
						|
	
 | 
						|
	if( line_string[0]=='\0' || line_string[0]==';'||line_string[0]=='%'||line_string[0]=='*')
 | 
						|
	    	return(0);
 | 
						|
        //remove anything after a ; if one exist
 | 
						|
        tmpc=line_string;
 | 
						|
        while( *tmpc !=  ';' &&*tmpc != '\0')
 | 
						|
                tmpc++;
 | 
						|
        *tmpc='\0';
 | 
						|
 | 
						|
        //check for a leading symbol
 | 
						|
	if( line_string[0] != ' ' && line_string[0] != '\t'){
 | 
						|
		
 | 
						|
		if(strlen(leading_symbol=strtok(line_string,": \t\n"))>MAX_SYM_LEN ){
 | 
						|
			printf("symbol \"%s\" is more than %d characters long\n",leading_symbol,MAX_SYM_LEN );
 | 
						|
			as_exit("Parse error");
 | 
						|
                }
 | 
						|
		
 | 
						|
                //address ref for skip command:
 | 
						|
                if(*leading_symbol=='.'){
 | 
						|
                        if( issymbol(leading_symbol,&sym)!=-1)
 | 
						|
                                (sym->data.value)+=ip-1;
 | 
						|
                }
 | 
						|
		op_name_ptr=strtok(NULL, " \t\n");  
 | 
						|
        }else{
 | 
						|
                op_name_ptr=strtok(line_string, " \t\n");
 | 
						|
        }
 | 
						|
                
 | 
						|
	if(op_name_ptr==NULL)
 | 
						|
		return(0);
 | 
						|
 | 
						|
	        
 | 
						|
        //check if it a macro:
 | 
						|
        if((tmp=ismacro(op_name_ptr)) != -1 ){
 | 
						|
                if(defmacro==0)
 | 
						|
                        macro_expand(tmp,strtok(NULL,""));
 | 
						|
			return(0);
 | 
						|
        }
 | 
						|
	
 | 
						|
        if( (op_num=op_decode(op_name_ptr))==-1) {
 | 
						|
                printf("**Parse Error with op code field \"%s\"\n",op_name_ptr);
 | 
						|
                as_exit("Parse Error: Bad neumonic");
 | 
						|
        }
 | 
						|
	
 | 
						|
	//check to see if we're defining a macro
 | 
						|
	if(leading_symbol!=NULL && defmacro!=0 && op_num!=CON && op_num!=CONSTANT)
 | 
						|
		as_exit("Parse error: Cannot define symbols inside of a macro");
 | 
						|
                      
 | 
						|
             
 | 
						|
        switch(op_num){
 | 
						|
                
 | 
						|
        case EQU:
 | 
						|
                add_symbol(leading_symbol,GPR_TYPE_EQUATE,arg_decode(strtok(NULL, " \t\n"),0),0);
 | 
						|
                return(0);
 | 
						|
                
 | 
						|
        case DS:
 | 
						|
                printf("**Assembler warning: \"DS\" will be obsoleted\n");
 | 
						|
        case DYNAMIC:
 | 
						|
        case DYN:
 | 
						|
                add_symbol(leading_symbol,GPR_TYPE_DYNAMIC,ds_addr++,0);
 | 
						|
 | 
						|
                if( (tmpc=strtok(NULL, " \t\n"))==NULL)
 | 
						|
                        tmp=0;
 | 
						|
                else if((tmp=arg_decode(tmpc,0)) <=0)
 | 
						|
                        tmp=1;
 | 
						|
                for(i=1;i<tmp;i++){
 | 
						|
                        add_symbol( (char *)NO_SYM ,GPR_TYPE_DYNAMIC,ds_addr++,0);
 | 
						|
 | 
						|
                }
 | 
						|
                return(0);
 | 
						|
        case MACRO:
 | 
						|
                new_macro(leading_symbol,line,strtok(NULL, "")-line_string+line);
 | 
						|
                defmacro++;
 | 
						|
                return(0);                                
 | 
						|
        case DC:
 | 
						|
                printf("**Assembler warning: \"DC\" will be obsoleted\n");
 | 
						|
        case STA:
 | 
						|
        case STATIC:
 | 
						|
                tmpc = strtok(NULL, " ,\t\n") ;
 | 
						|
                
 | 
						|
                if(tmpc == NULL)
 | 
						|
                        as_exit("Error DC directive must contain an initial value");
 | 
						|
                while(tmpc!=NULL ){
 | 
						|
                        
 | 
						|
                        if(  tmpc[0] == '&' )
 | 
						|
                                tmp=arg2long(tmpc)*0x800; //account for 11 bit shift of addresses
 | 
						|
                        else
 | 
						|
                                tmp=arg2long(tmpc);
 | 
						|
 | 
						|
                        add_symbol(leading_symbol,GPR_TYPE_STATIC,ds_addr++,tmp);
 | 
						|
 | 
						|
                        leading_symbol=(char *)NO_SYM;
 | 
						|
                        
 | 
						|
			tmpc=strtok(NULL, " ,\t");
 | 
						|
                }
 | 
						|
                return(0);
 | 
						|
 | 
						|
        case CONSTANT:
 | 
						|
        case CON:
 | 
						|
		//declaring constants inside of a macro is legal and needed for branch macros
 | 
						|
		if(defmacro!=0)
 | 
						|
			return (0);
 | 
						|
		
 | 
						|
 | 
						|
		tmpc = strtok(NULL, " ,\t\n") ;
 | 
						|
                
 | 
						|
                if(tmpc == NULL)
 | 
						|
                        as_exit("Error Constant directive must contain a value");
 | 
						|
                while(tmpc!=NULL ){
 | 
						|
                        
 | 
						|
                        if(  tmpc[0] == '&' )
 | 
						|
                                tmp=arg2long(tmpc)*0x800; //account for 11 bit shift of addresses
 | 
						|
                        else
 | 
						|
                                tmp=arg2long(tmpc);
 | 
						|
                        
 | 
						|
			//     add_constant(leading_symbol,tmp);
 | 
						|
			
 | 
						|
			add_symbol(leading_symbol,GPR_TYPE_CONSTANT,ds_addr++,tmp);
 | 
						|
                        
 | 
						|
			leading_symbol=(char *)NO_SYM;
 | 
						|
                        
 | 
						|
                        tmpc=strtok(NULL, " ,\t");
 | 
						|
                }
 | 
						|
		
 | 
						|
                return(0);
 | 
						|
        case IO:
 | 
						|
                add_symbol(leading_symbol,GPR_TYPE_INPUT,ds_addr++,0);
 | 
						|
                add_symbol(strcat(leading_symbol,".o"),GPR_TYPE_OUTPUT,ds_addr++,0);
 | 
						|
                return(0);
 | 
						|
        case DIN:
 | 
						|
                as_exit("DIN is obsoleted, use IO instead");
 | 
						|
                add_symbol(leading_symbol,GPR_TYPE_INPUT,ds_addr++,0);
 | 
						|
                return(0);
 | 
						|
        case DOUT:
 | 
						|
                as_exit("DOUT is obsoleted, use IO instead");
 | 
						|
                        add_symbol(leading_symbol,GPR_TYPE_OUTPUT,ds_addr++,0);
 | 
						|
                        return(0);
 | 
						|
        case DD:
 | 
						|
		add_symbol(leading_symbol,GPR_TYPE_EQUATE,0x100+tram_delay_count,0);
 | 
						|
		(&tram_delay[tram_delay_count])->size = arg2long( strtok(NULL, " \t\n" ) ) +1;
 | 
						|
		
 | 
						|
		INIT_LIST_HEAD( &(tram_delay[tram_delay_count].tram  )  );
 | 
						|
		strcpy((&tram_delay[tram_delay_count])->name,leading_symbol);
 | 
						|
		if((dbg_opt&DBG_TRAM))
 | 
						|
			printf("Delay Line:  %-16s, length: 0x%05x samples,\n",(&tram_delay[tram_delay_count])->name, (&tram_delay[tram_delay_count])->size);
 | 
						|
		tram_delay_count++;
 | 
						|
                        return(0);
 | 
						|
        case DT:
 | 
						|
                add_symbol(leading_symbol,GPR_TYPE_EQUATE,tram_table_count,0);
 | 
						|
                (&tram_lookup[tram_table_count])->size = arg2long( strtok(NULL, " \t\n" ) );
 | 
						|
                INIT_LIST_HEAD(   &(tram_lookup[tram_table_count].tram) );
 | 
						|
		strcpy((&tram_lookup[tram_table_count])->name,leading_symbol);
 | 
						|
		
 | 
						|
		if((dbg_opt&DBG_TRAM))
 | 
						|
			printf("Lookup table: %-16s, length: 0x%05x samples\n",leading_symbol, (&tram_delay[tram_delay_count])->size);
 | 
						|
		tram_table_count++;
 | 
						|
                        return(0);
 | 
						|
        case DW:
 | 
						|
                //two symbols are created, "symbol"   ->  addr:0x2xx ; value: tram id #
 | 
						|
                //                         "symbol.a" ->  addr:0x3xx ; value: write offset
 | 
						|
		
 | 
						|
		add_symbol(leading_symbol,TYPE_TRAM_DATA,tram_addr+0x200, arg_decode(tmpc=strtok(NULL, " \t," ),0) );
 | 
						|
		add_symbol( strcat(leading_symbol,".a") ,TYPE_TRAM_ADDR_WRITE, (tram_addr++)+0x300 ,
 | 
						|
                            arg2long(strtok(NULL," \t\n")));
 | 
						|
		if(dbg_opt&DBG_TRAM)
 | 
						|
			printf(", in segment: \"%s\"\n",tmpc);
 | 
						|
		
 | 
						|
		return(0);
 | 
						|
 | 
						|
	case DR:
 | 
						|
		add_symbol(leading_symbol,TYPE_TRAM_DATA,tram_addr+0x200,arg_decode(tmpc=strtok(NULL, " \t," ),0) );
 | 
						|
		add_symbol(strcat(leading_symbol,".a"),TYPE_TRAM_ADDR_READ,(tram_addr++)+0x300,
 | 
						|
                           arg2long(strtok(NULL," \t\n")));
 | 
						|
		if(dbg_opt&DBG_TRAM)
 | 
						|
			printf(", in segment: \"%s\"\n",tmpc);
 | 
						|
		return(0);
 | 
						|
        case CONTROL:
 | 
						|
			if( (tmpc = strtok(NULL, "\t ,\n")) ==NULL)
 | 
						|
			    as_exit("Parse Error: missing operand(s)");
 | 
						|
			    
 | 
						|
                        if(  tmpc[0] == '&' )
 | 
						|
                                tmp=arg2long(tmpc)<<11; //account for 11 bit shift of addresses
 | 
						|
                        else
 | 
						|
                                tmp=arg2long(tmpc);
 | 
						|
                        add_symbol(leading_symbol,GPR_TYPE_CONTROL,ds_addr++,tmp);
 | 
						|
                        issymbol(leading_symbol,(struct sym **)(&control));
 | 
						|
 | 
						|
 | 
						|
                        if( (tmpc = strtok(NULL, "\t ,\n") )==NULL)
 | 
						|
			    as_exit("Parse Error: missing operand(s)");
 | 
						|
                       
 | 
						|
 | 
						|
                        if(  tmpc[0] == '&' ) 
 | 
						|
                                control->min=arg2long(tmpc)<<11; //account for 11 bit shift of addresses
 | 
						|
                        else
 | 
						|
                                control->min=arg2long(tmpc);
 | 
						|
			
 | 
						|
			if( (tmpc = strtok(NULL, "\t ,\n")) ==NULL)
 | 
						|
			    as_exit("Parse Error: missing operand(s)");
 | 
						|
 | 
						|
                       
 | 
						|
                        if(  tmpc[0] == '&' ) 
 | 
						|
                                control->max=arg2long(tmpc)<<11; //account for 11 bit shift of addresses
 | 
						|
                        else
 | 
						|
                                control->max=arg2long(tmpc);
 | 
						|
                        
 | 
						|
                        return(0);
 | 
						|
        case ENDM:
 | 
						|
                        if(defmacro==1) {
 | 
						|
                                defmacro--;
 | 
						|
                                return(0);
 | 
						|
                        }else if(macro_depth!=0)
 | 
						|
                                return(-1);
 | 
						|
                        else
 | 
						|
                                as_exit("Error, stray ENDM directive");
 | 
						|
        case END:
 | 
						|
                        if(defmacro==1)
 | 
						|
                                as_exit("Error end directive in macro definition");
 | 
						|
                        return(1);	
 | 
						|
        case INCLUDE:
 | 
						|
                if(defmacro==1)
 | 
						|
                        as_exit("Error, cannot include file from within macro definition");
 | 
						|
		if(listing){
 | 
						|
			sprintf(listtemp,"including file");
 | 
						|
			fprintf(listfile,"%-50s ||   %s\n",listtemp,line);
 | 
						|
                }
 | 
						|
		asm_open(strtok(NULL, "\'\""));
 | 
						|
		
 | 
						|
                return(-3);
 | 
						|
        case NAME:
 | 
						|
                advance_to_end(op_name_ptr);
 | 
						|
                op_name_ptr++;
 | 
						|
                advance_over_whites(op_name_ptr);
 | 
						|
		if(dbg_opt)
 | 
						|
			printf("Patch name:%s\n",op_name_ptr);
 | 
						|
 | 
						|
		//	printf("%s\n",op_name_ptr);
 | 
						|
                tmpc=strtok(op_name_ptr,"\"");
 | 
						|
                if(tmpc==NULL)
 | 
						|
                        as_exit("Bad name string, did you remember quotes\"\"");
 | 
						|
                if(strlen(tmpc)>PATCH_NAME_SIZE)
 | 
						|
                        as_exit("Error Patch name exceeds maximum allowed amount (16)");
 | 
						|
		memset(patch_name,0,PATCH_NAME_SIZE);
 | 
						|
                strcpy(patch_name,tmpc);
 | 
						|
                return(0);
 | 
						|
        case FOR:
 | 
						|
		if(listing){
 | 
						|
			sprintf(listtemp,"FOR LOOP");
 | 
						|
			fprintf(listfile,"%-50s ||   %s\n",listtemp,line);
 | 
						|
                }
 | 
						|
                for_handler(line,strtok(NULL,""));
 | 
						|
		
 | 
						|
                return(-3);
 | 
						|
        case ENDFOR:
 | 
						|
		sprintf(listtemp,"FOR LOOP DONE");
 | 
						|
                return(-2);
 | 
						|
        default:
 | 
						|
                
 | 
						|
                if(defmacro==0){
 | 
						|
			
 | 
						|
                        for(i=0;i<=3;i++)
 | 
						|
                                arg[i]=arg_decode(strtok(NULL,","),0);
 | 
						|
                        op(op_num,arg[0],arg[1],arg[2],arg[3]);
 | 
						|
                        return(0);
 | 
						|
 | 
						|
                }else
 | 
						|
                        return(0);
 | 
						|
        }
 | 
						|
        return(0);
 | 
						|
}
 | 
						|
//assembly-time for loop handling:
 | 
						|
void for_handler(char *begin, char *operand )
 | 
						|
{
 | 
						|
        char *ptr,*next,*line,string[MAX_LINE_LENGTH];
 | 
						|
        int start,end,i,done;
 | 
						|
        int diff, incr=1;
 | 
						|
        struct sym *sym;
 | 
						|
        
 | 
						|
        ptr=strtok(operand,"=");
 | 
						|
 | 
						|
        start= arg_decode(strtok(NULL,":"),0);
 | 
						|
        end  = arg_decode(strtok(NULL," \t"),0);
 | 
						|
 | 
						|
        
 | 
						|
        if(end>start)
 | 
						|
                diff=end-start;
 | 
						|
        else{
 | 
						|
                diff=start-end;
 | 
						|
                incr=-1;
 | 
						|
        }
 | 
						|
        
 | 
						|
        if( (issymbol(ptr,&sym))!=-1)
 | 
						|
                sym->data.address=start;
 | 
						|
        else
 | 
						|
                add_symbol(ptr,GPR_TYPE_EQUATE, start,0);
 | 
						|
        
 | 
						|
        issymbol(ptr,&sym);
 | 
						|
        
 | 
						|
        
 | 
						|
        while(*begin!='\0')
 | 
						|
                begin++;
 | 
						|
        begin++;
 | 
						|
        
 | 
						|
        for(i=0;i<diff;i++){
 | 
						|
                next=begin;
 | 
						|
                line=next;
 | 
						|
                done=0;
 | 
						|
                
 | 
						|
                while(done==0)
 | 
						|
                {
 | 
						|
                        while((*next!= '\n') )
 | 
						|
                                next++;
 | 
						|
			listtemp[0]='\0';
 | 
						|
                        *next='\0';
 | 
						|
                        if(strlen(line)>MAX_LINE_LENGTH)
 | 
						|
                                as_exit("Parse error: Line exceeds allowable limit");
 | 
						|
                        strcpy(&string[0],line);
 | 
						|
                        //printf("%s\n",string);
 | 
						|
                        done=parse(string, line);
 | 
						|
			if(listing)
 | 
						|
				if(done!=-2)
 | 
						|
					fprintf(listfile,"%-50s ||   %s\n",listtemp,line);
 | 
						|
                        *next='\n';
 | 
						|
                        if(done==-2)
 | 
						|
                                break;
 | 
						|
                        next++;
 | 
						|
                
 | 
						|
                
 | 
						|
                        line=next;          
 | 
						|
                }
 | 
						|
                sym->data.address = start+(incr*(i+1));
 | 
						|
               
 | 
						|
        }
 | 
						|
 | 
						|
	
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
int op_decode(char *op_name_ptr)
 | 
						|
{
 | 
						|
	int op_num;
 | 
						|
 | 
						|
	for(op_num=0;op_num<NUM_OPS;op_num++){
 | 
						|
      		if( strcasecmp(&op_codes[op_num][0],op_name_ptr) == 0 )
 | 
						|
			return(op_num);
 | 
						|
    	}
 | 
						|
	return(-1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//check if a symbol is used and returns it's pointer value in sym 
 | 
						|
//normally returns 0, if symbol is non exitant, return -1
 | 
						|
 | 
						|
int issymbol(char *symbol,struct sym **sym)
 | 
						|
{
 | 
						|
        extern unsigned int macro_depth;
 | 
						|
        extern struct list_head sym_head;
 | 
						|
        struct list_head *entry;
 | 
						|
 | 
						|
        
 | 
						|
        list_for_each(entry,&sym_head){
 | 
						|
                (*sym)=list_entry(entry,struct sym,list);
 | 
						|
                if(symcmp((char *)&(*sym)->data.name,symbol)==0){
 | 
						|
                        if((*sym)->type!=TYPE_MACRO_ARG)
 | 
						|
                                return(0);
 | 
						|
                        else if( (*sym)->data.value==(macro_depth+1) )
 | 
						|
                                return(0);
 | 
						|
                }
 | 
						|
                
 | 
						|
                        
 | 
						|
        }
 | 
						|
  
 | 
						|
        return(-1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//compares to words, the words can be terminated with a ' ', '\t',  ',' or '\0'
 | 
						|
int symcmp (char *symbol1,char *symbol2)
 | 
						|
{
 | 
						|
 | 
						|
        
 | 
						|
        while(1){
 | 
						|
                if(*symbol1!=*symbol2)
 | 
						|
                        return(-1);
 | 
						|
                symbol1++;
 | 
						|
                symbol2++;
 | 
						|
                
 | 
						|
                if(symend(symbol1) && symend(symbol2))
 | 
						|
                        return(0);
 | 
						|
                
 | 
						|
        }
 | 
						|
        
 | 
						|
        
 | 
						|
}
 | 
						|
 | 
						|
//copies a symbol, symbols can be terminated with a ' ' ,  '\t' ,  ','  ,  '\n'  ,  a '\0'
 | 
						|
void symcpy (char *dest, char *source)
 | 
						|
{  int i=0;
 | 
						|
        for(i=0;i<=MAX_SYM_LEN;i++){
 | 
						|
                if(source[i]== ' ' || source[i]=='\0' ||source[i]==',' ||source[i]=='\n' || source[i]=='\t'  ) {
 | 
						|
                        dest[i]='\0';
 | 
						|
                        return;
 | 
						|
                }
 | 
						|
                dest[i]=source[i];
 | 
						|
        }
 | 
						|
        as_exit("Error, Maximum symbol length exceeded");
 | 
						|
       
 | 
						|
       
 | 
						|
}
 |