home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************
- * 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);
- }
-