home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
215.lha
/
GlueMaker_v1.0
/
GlueMaker.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-15
|
19KB
|
706 lines
/*****************************************************************
* GlueMaker - makes glue routines from .fd files - by Talin *
* Copyright (c) 1989 Elf Tech *
*****************************************************************
* Revision History: *
* Version 1.0 - Released 4 Feb 1989 *
*****************************************************************/
#include "exec/types.h"
#include "exec/memory.h"
#include "libraries/dosextens.h"
#include "setjmp.h"
#include "stdio.h"
#define NEWLINE 0x0a
#define RETURN 0x0d
#define TAB 0x09
#define MEM_SIZE 30000 /* 30 K */
/* file buffer variables */
void *AllocMem();
APTR Open();
LONG in_size; /* size of input file (.fd) */
char *memstart=NULL, /* start of file in memory */
*memend; /* end of file in memory */
/* parsing variables */
char *scan, /* current scan point in source */
*put, /* address of string to insert */
*name,
*line_start, /* start of current line */
*find_line_end(); /* find ending CR */
LONG nval, /* numeric value parsed */
txlen, /* text string parsed */
digits, /* # of digits parsed */
linenum; /* current line number */
UBYTE priv_flag, /* ##private flag */
jump_flag; /* jump flag */
short reg_num, /* register number, 0-15 */
regs_saved, /* number of registers saved on stack */
arg_count;
UWORD regs_used; /* registers used, flag bits */
BYTE reg_args[16], /* registers passed as parameters */
reg_sizes[16], /* and what size the args were */
reg_type[16]; /* if we needed an lea */
UBYTE savestring[50]; /* movem register list for save/restore */
UBYTE argstring[50]; /* movem register list for unstack */
/* te following table defines which regs may be used, which need to be restored,
etc. It may be changed to alter the register model.
*/
#define REG_SCRATCH 0 /* ok to use this register as scratch */
#define REG_PRESERVE 1 /* preserve this register */
#define REG_SPECIAL 2 /* leave this register alone */
UBYTE reg_protect[] = {
REG_SCRATCH, /* d0 */
REG_SCRATCH, /* d1 */
REG_SCRATCH, /* d2 */
REG_SCRATCH, /* d3 */
REG_PRESERVE, /* d4 */
REG_PRESERVE, /* d5 */
REG_PRESERVE, /* d6 */
REG_PRESERVE, /* d7 */
REG_SCRATCH, /* a0 */
REG_SCRATCH, /* a1 */
REG_PRESERVE, /* a2 */
REG_PRESERVE, /* a3 */
REG_PRESERVE, /* a4 */
REG_PRESERVE, /* a5 */
REG_SPECIAL, /* a6 */
REG_SPECIAL, /* a7 */
};
jmp_buf env; /* setjmp for errors */
UBYTE boldstring[] = { 0x1b, '[' }; /* to print boldface on CON: */
UBYTE unboldstring[] = { 0x1b, '[' }; /* to print normal on CON: */
#define SCAT goto exit_pgm; /* standard exit macro */
#define EOB(x) (x >= memend) /* end of buffer */
char *seek_char(), *reg_string(),*rindex();
APTR gluefile=NULL; /* file handle of current output file */
extern int Enable_Abort; /* used by Chk_Abort */
main(argc, argv) LONG argc; UBYTE **argv;
{ APTR infile=NULL, makefile=NULL, vectorfile=NULL, lvofile=NULL;
short jmp=0,
length;
static char /* yn[2], */ /* yes or no */
libname[40], /* name of library we are gluemaking */
lvoname[40], /* name of lvo file */
filename[80],
funcname[40], /* name of current .fd function */
basename[40], /* name of library base */
jumpname[40], /* for ##jump directive */
vectorfilename[80], /* pathname of 'vector.i' file */
gluefilepath[80], /* path for glue files */
gluefilename[120]; /* name of current output file */
LONG flength, /* lengths of above strings */
mflength,
vflength,
gplength=0;
if (!Input()) return 0; /* can't run from workbench */
Enable_Abort = 0; /* don't abort, let me handle it */
if (jmp = setjmp(env)) SCAT; /* set jump for error */
if (argc != 2)
{ puts("GlueMaker - By Talin.");
puts("Usage: GlueMaker <input file>");
puts("");
puts("The glue file has 5 parameters:");
puts("FDFILE=filename (name of funcdef file, '.fd' added.)");
puts("OUTDIR=dirname (name of directory to put asm routines)");
puts("LIBFILE=filename (name of resulting link library, '.lib' added)");
puts("PROTECT (use this to preserve d2/d3 in glue routines)");
puts("");
SCAT;
}
{ FILE *fd = fopen(argv[1],"r");
char inbuf[128],*c;
if (!fd) error("Cannot open input file.");
while (fgets(inbuf,128,fd))
{ if (inbuf[0])
{ if (c = rindex(inbuf,'\n')) *c = 0;
if (!strncmp(inbuf,"FDFILE=",7)) strcpy(filename,&inbuf[7]);
else if (!strncmp(inbuf,"OUTDIR=",7)) strcpy(gluefilepath,&inbuf[7]);
else if (!strncmp(inbuf,"LIBFILE=",8)) strcpy(libname,&inbuf[8]);
else if (!strncmp(inbuf,"PROTECT",7))
{ reg_protect[2] = reg_protect[3] = REG_PRESERVE; }
else error("Unrecognized option");
}
}
gplength = strlen(gluefilepath);
fclose(fd);
}
if (gplength > 0 && gluefilepath[gplength-1] != ':')
strcat(gluefilepath,"/");
strcat(filename,".fd"); /* name of input file */
if (!(memstart = AllocMem(MEM_SIZE,0))) error("Not Enough Memory.");
if (!(infile = Open(filename,MODE_OLDFILE))) error("Couldn't open input file.");
in_size = Read(infile,memstart,MEM_SIZE);
Close(infile); infile = NULL;
if (in_size >= MEM_SIZE) error("Input File Too Big.");
printf("Read %ld bytes from source file.\n",in_size);
line_start = scan = memstart;
memend = memstart + in_size;
priv_flag = jump_flag = FALSE;
/* now build the LVO file path string */
strcpy(gluefilename,gluefilepath);
strcat(gluefilename,libname);
strcat(gluefilename,"_lvo.asm");
if (!(lvofile = Open(gluefilename,MODE_NEWFILE)))
error("Couldn't open lvo file.");
strcpy(vectorfilename,gluefilepath);
strcat(vectorfilename,libname);
strcat(vectorfilename,"_lvo.i");
if (!(vectorfile = Open(vectorfilename,MODE_NEWFILE)))
error("Couldn't open vector file.");
strcpy(gluefilename,gluefilepath);
strcat(gluefilename,"makefile");
if (!(makefile = Open(gluefilename,MODE_NEWFILE)))
error("Couldn't open make file.");
/* now, start parsing the file */
APrintf(makefile,"#\n# makefile for %s.lib - created by GlueMaker\n#\n\n",libname);
APrintf(makefile,".asm.o:\n as -D -C -o $@ $*.asm\n\n");
APrintf(makefile,"OBS=");
APrintf(vectorfile,"* Vector list for glue routines.\n\n");
while (TRUE)
{ abortcheck();
if (match_word("##base"))
{ /* get the global base variable... */
whitespace();
put = basename;
if (!get_symbol(40)) fatal("Base name too long.");
if (txlen == 0) fatal("Invalid base name.");
printf("Library Base Pointer is <%s>.\n",basename);
}
else if (match_word("##jump"))
{ whitespace();
put = jumpname;
if (!get_symbol(40)) fatal("Jump name too long.");
if (txlen == 0) jump_flag = FALSE; else jump_flag = TRUE;
}
else if (match_word("##bias"))
{ get_number();
/* get the library bias... */
/* I don't know how the library bias is used, so... */
printf("Bias is: <%ld>.\n",nval);
}
else if (match_word("##private"))
{ /* set the 'private' flag.. (don't generate glue files) */
priv_flag = TRUE;
}
else if (match_word("##public")) priv_flag = FALSE; /* set private off */
else if (match_word("##end")) break; /* done */
else if (match_word("*")) { ; } /* comment */
else
{ /* it's a definition */
put = funcname;
if (!get_symbol(40)) fatal("Function name too long.");
if (txlen == 0) fatal("Invalid symbol name.");
printf("Defining %s.\n",funcname);
if (match_char('(')) /* function arguments... */
{ short i;
if (seek_char(')')) /* look for closing paren */
{ regs_saved = 0;
regs_used = NULL;
arg_count = 0;
if (match_char('(')) /* registers used */
{ while (TRUE)
{ if (match_char(')')) break;
reg_sizes[arg_count] = 4; /* size = longword */
reg_type[arg_count] = 0; /* normal */
if (match_char('&')) reg_type[arg_count] = 1;
if (get_register())
{ if (match_word(".l") || match_word(".L"))
reg_sizes[arg_count] = 4;
else if (match_word(".w") || match_word(".W"))
reg_sizes[arg_count] = 2;
else if (match_word(".b") || match_word(".B"))
reg_sizes[arg_count] = 1;
reg_args[arg_count++] = reg_num;
if (arg_count >= 16) fatal("Too many arguments");
if (reg_protect[reg_num] == REG_SPECIAL)
fatal("Can't use that register.");
else if (regs_used & (1<<reg_num))
fatal("Already used that register");
regs_used |= 1<<reg_num;
if (reg_protect[reg_num] == REG_PRESERVE)
regs_saved++;
/* now get the delimeter... */
if (match_char('/') || match_char(',')) ;
}
else fatal ("Delimeter Expected.");
}
}
/* now, write out the routine...*/
abortcheck();
APrintf(vectorfile," LIBVEC %s\n",funcname);
if (priv_flag) goto priv;
APrintf(makefile," %s.o \\\n",funcname);
strcpy(gluefilename,gluefilepath);
strcat(gluefilename,funcname);
strcat(gluefilename,".asm");
if (!(gluefile = Open(gluefilename,MODE_NEWFILE)))
error("Couldn't open glue source file.");
/* APrintf(gluefile,"\n**** Glue File: %s.c ****\n",funcname); */
APrintf(gluefile,"* Glue routine for %s() - created by GlueMaker\n",funcname);
APrintf(gluefile,"*\n");
APrintf(gluefile,"* ");
Write(gluefile,line_start,scan-line_start);
APrintf(gluefile,"\n*\n");
APrintf(gluefile," xref %s,_LVO%s\n",
basename,funcname);
APrintf(gluefile," xdef _%s\n",funcname);
if (jump_flag) APrintf(gluefile," xref %s\n",
jumpname);
APrintf(gluefile,"_%s:\n",funcname);
if (regs_saved > 1)
{ reg_move_string(); /* create movem string */
APrintf(gluefile," movem.l %s,-(sp)\n",savestring);
}
else if (regs_saved)
{ reg_move_string();
APrintf(gluefile," move.l %s,-(sp)\n",savestring);
}
reg_params(4+4*regs_saved);
APrintf(gluefile," move.l %s,a6\n",basename);
if (regs_saved)
{ APrintf(gluefile," jsr _LVO%s(a6)\n",funcname);
if (regs_saved==1)
{ APrintf(gluefile,"\t\t\tmove.l (sp)+,%s\n",savestring);
}
else APrintf(gluefile,"\t\t\tmovem.l (sp)+,%s\n",savestring);
if (jump_flag)
APrintf(gluefile,"\t\t\tbra %s\n",jumpname);
else APrintf(gluefile,"\t\t\trts\n");
}
else
{ if (jump_flag)
APrintf(gluefile,"\t\t\tpea %s\n",jumpname);
APrintf(gluefile,"\t\t\tjmp _LVO%s(a6)\n",funcname);
}
Close(gluefile);
gluefile = NULL;
priv: ;
}
else fatal("Matching parenthesis needed");
}
else fatal("Arguments not defined.");
/* now, skip the arguments */
/* and get to the registers... (if any) */
}
/* skip to the next line - check for garbage on line? */
seek_eol();
}
APrintf(makefile,"\n\nall: $(OBS) %s_lvo.o\n lb %s.lib $(OBS) %s_lvo.o\n\n",libname,libname,libname);
APrintf(lvofile,
"* ======================================================================\n");
APrintf(lvofile,
"* Library Vector File for %s.lib\n",libname);
APrintf(lvofile,
"* Created By GlueMaker\n");
APrintf(lvofile,
"* ======================================================================\n");
APrintf(lvofile,"\n");
APrintf(lvofile,"\t\t\tINCLUDE\t\"exec/types.i\"\n");
APrintf(lvofile,"\t\t\tINCLUDE\t\"exec/libraries.i\"\n");
APrintf(lvofile,"\n");
APrintf(lvofile,"LIBVEC\t\tMACRO\n");
APrintf(lvofile,"\t\t\txdef\t_LVO\\1\n");
APrintf(lvofile,"_LVO\\1\t\tequ\t\tCOUNT_LIB\n");
APrintf(lvofile,"COUNT_LIB\tset\t\tCOUNT_LIB-LIB_VECTSIZE\n");
APrintf(lvofile,"\t\t\tendm\n");
APrintf(lvofile,"\n");
APrintf(lvofile,"\t\t\tLIBINIT\n");
APrintf(lvofile,"\n");
APrintf(lvofile,"\t\t\tinclude\t\t\"%s_lvo.i\"\n",libname);
APrintf(lvofile,"\n");
APrintf(lvofile,"\t\t\tend\n");
puts("Exiting.");
exit_pgm:
if (gluefile) Close(gluefile);
if (lvofile) Close(lvofile);
if (makefile) Close(makefile);
if (vectorfile) Close(vectorfile);
if (memstart) FreeMem(memstart,MEM_SIZE);
}
/* print fatal global error message */
error(message) char *message;
{ printf("ERROR: %s.\n",message);
longjmp(env,1);
}
abortcheck()
{ if (Chk_Abort())
{ puts("Aborted.");
longjmp(env,1);
}
}
/* print fatal error message caused by specific line */
fatal(message) char *message;
{ char *current;
current = scan;
skip_line();
offending_line(current,scan);
printf("ERROR: %s on line %ld.\n",message,linenum);
longjmp(env,2);
}
/* print warning message */
warn(message) char *message;
{ char *end;
end = find_line_end();
offending_line(scan,end);
printf("WARNING: %s on line %ld.\n",message,linenum);
}
char underline_on[] = { 0x9b,'4','m',0 };
char underline_off[] = { 0x9b,'0','m',0 };
/* string copy with limits; works slightly different from strncpy() */
char *scpy(str1,str2,n) register char *str1,*str2; register long n;
{ char *hold;
hold = str1;
while (n-- && (*str1++ = *str2++)) ;
*str1 = '\0';
return (hold);
}
/* print out the line that caused the error */
offending_line(a,b) char *a,*b;
{ char stuff[80];
int i,j;
i = a - line_start;
j = b - a;
if (i > 79)
{ scpy(stuff,line_start,79);
printf("%s$\n",stuff);
return;
}
scpy(stuff,line_start,i);
printf("%s%s",stuff,underline_on);
if (i+j > 79)
{ scpy(stuff,a,79-i);
printf("%s$",stuff);
}
else
{ scpy(stuff,a,j);
printf(stuff);
}
printf("%s\n",underline_off);
}
match_char(c) char c;
{ whitespace();
if (*scan == c) { scan++; return TRUE; }
return FALSE;
}
/* match a word, case sensitive */
match_word(p) char *p;
{ char *s;
whitespace();
s = scan;
while (*p) if (*s++ != *p++) return FALSE;
scan = s;
return TRUE;
}
/* parse a number */
get_number()
{ whitespace();
digits = nval = 0;
while (*scan >= '0' && *scan <= '9')
{ nval = nval * 10 + (*scan++ - '0');
digits++;
}
}
/* expect a symbol name */
get_symbol(maxlen) short maxlen;
{ txlen = 0;
while ( (*scan >= 'a' && *scan <= 'z') ||
(*scan >= 'A' && *scan <= 'Z') ||
(*scan >= '0' && *scan <= '9') ||
*scan == '_' )
{ if (txlen >= maxlen-2) { *put++=0; return FALSE; }
*put++=*scan++; txlen++;
}
*put++ = 0;
return TRUE;
}
/* skip until a certain character is found */
char *seek_char(c) char c;
{ char *s;
s = scan;
while (!EOB(s) && *s != RETURN && *s != NEWLINE && *s != ';')
{ if (*s++ == c) return scan=s; }
return NULL;
}
/* skip over blank characters */
whitespace()
{ while (*scan == ' ' || *scan == TAB) scan++;
}
/* skip this line, maintain error-handling info */
seek_eol()
{ while (!(EOB(scan)))
{ if (*scan == RETURN || *scan == NEWLINE)
{ linenum++;
line_start = scan + 1;
scan++;
break;
}
else scan++;
}
}
skipcomma()
{ whitespace();
if (*scan == ',') scan++;
}
skip()
{ while (!EOB(scan) && *scan != NEWLINE && *scan != RETURN) scan++;
}
skip_line()
{ scan = find_line_end();
}
/* find end of line, do not change error-handling info */
char *find_line_end()
{ char *at;
at = scan;
while (*at != RETURN && *at != NEWLINE) at++;
return at;
}
/* parse a register name */
get_register()
{ char c;
if (match_char('a') || match_char('A')) reg_num = 8;
else if (match_char('d') || match_char('D')) reg_num = 0;
else return FALSE;
c = *scan++;
if (c >= '0' && c <= '9') reg_num += (c - '0');
else return FALSE;
return TRUE;
}
char rstring[3] = "A0";
/* return a register name, given the number */
char *reg_string(regnum) short regnum;
{ ins_regname(regnum,rstring);
return rstring;
}
/* insert a register name into a byte array */
ins_regname(regnum,string) short regnum; char *string;
{ if (regnum & 8) *string++ = 'A'; else *string++ = 'D';
*string++ = '0' + (regnum & 7);
}
/* generate a 'movem'-style register string. */
UBYTE regbuf[17]; /* 16 registers */
/* I use 17 as a sentinel case */
reg_move_string()
{ short i, reg, runstart, runlength, runflag;
UBYTE *str=savestring;
/* first, clear all the elements in the array to zero */
for (i=0; i<17; i++) regbuf[i] = 0;
/* now, mark off the registers that need to be saved */
for (i=0; i<arg_count; i++)
{ reg = reg_args[i]; /* get the register that was used */
if (reg_protect[reg] == REG_PRESERVE)
{ regbuf[reg] = 1;
}
}
/* now, figure out which ones have runs... */
runstart = -1; /* not in a run */
for (i=0; i<17; i++)
{ /* start of run */
if (runstart >= 0)
{ if (regbuf[i] == 0 || i == 8) /* cut off run starting at A0 */
{ runlength = i - runstart;
if (str != savestring) *str++ = '/'; /* seperator */
if (runlength==1) { ins_regname(runstart,str); str += 2; }
else
{ ins_regname(runstart,str); str+=2;
*str++ = '-';
ins_regname(i-1,str); str+=2;
}
runstart = -1;
}
}
if (runstart < 0 && regbuf[i]) { runstart = i; }
}
*str++ = 0;
}
/* see which parameters can be filled via 'movem' */
reg_params(offset)
{ short i, last, runlength, reg;
UBYTE *str=argstring;
last = -1; /* last register pushed (none) */
runlength = 0;
if (arg_count == 0) return;
for (i=0; i<arg_count; i++)
{ reg = reg_args[i];
if (reg > last && !reg_type[i] && runlength >= 0) runlength++;
else
{ *str++ = 0;
if (runlength < 0)
APrintf(gluefile,"\t\t\tlea.l %ld(sp),%s\n",offset,argstring);
else if (runlength)
APrintf(gluefile,"\t\t\tmovem.l %ld(sp),%s\n",offset,argstring);
else APrintf(gluefile,"\t\t\tmove.l %ld(sp),%s\n",offset,argstring);
if (runlength < 0) offset += 4;
else offset += (runlength * 4);
str = argstring;
if (reg_type[i]) runlength = -1;
else runlength = 1;
}
if (runlength>1) *str++ = '/';
ins_regname(reg,str); str+=2;
last = reg;
}
*str++ = 0;
if (runlength < 0) APrintf(gluefile,"\t\t\tlea.l %ld(sp),%s\n",offset,argstring);
else if (runlength) APrintf(gluefile,"\t\t\tmovem.l %ld(sp),%s\n",offset,argstring);
else APrintf(gluefile,"\t\t\tmove.l %ld(sp),%s\n",offset,argstring);
}
#define MAXLINE 128
APTR afile;
UWORD APrint_size;
char abuf[MAXLINE+1];
a_put_char(c) char c;
{ abuf[APrint_size++] = c;
if (APrint_size >= MAXLINE || c == '\n')
{ Write(afile,abuf,APrint_size);
APrint_size = 0;
}
}
/* APrintf - printfs into AmigaDOS file handle */
APrintf(file,string,args) APTR file; char *string; LONG args;
{ APrint_size = 0; /* start at zero */
afile = file;
format(a_put_char,string,&args); /* format the string */
if (APrint_size) { Write(file,abuf,APrint_size); APrint_size = 0; }
}
GetLine(string,length) char *string; short length;
{ char *c;
fgets(string,length,stdin);
if (c = rindex(string,'\n')) *c = 0;
abortcheck();
return strlen(string);
}