1*596Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*596Sbill static char sccsid[] = "@(#)asmain.c 4.1 08/13/80"; 3*596Sbill #include <stdio.h> 4*596Sbill #include <ctype.h> 5*596Sbill #include <sys/types.h> 6*596Sbill #include <signal.h> 7*596Sbill #include <a.out.h> 8*596Sbill 9*596Sbill #include "as.h" 10*596Sbill #include "assyms.h" 11*596Sbill #include "asexpr.h" 12*596Sbill #include "asscan.h" 13*596Sbill 14*596Sbill #ifdef UNIX 15*596Sbill #define unix_lang_name "VAX/UNIX Assembler V3.0" 16*596Sbill #endif 17*596Sbill 18*596Sbill #ifdef VMS 19*596Sbill #define vms_lang_name "VAX/VMS C assembler V1.00" 20*596Sbill #endif VMS 21*596Sbill 22*596Sbill /* 23*596Sbill * variables to manage reading the assembly source files 24*596Sbill */ 25*596Sbill char *dotsname; /*the current file name; managed by the parser*/ 26*596Sbill int lineno; /*current line number; managed by the parser*/ 27*596Sbill char *innames[32]; /*names of the files being assembled*/ 28*596Sbill int ninfiles; /*how many interesting files there are*/ 29*596Sbill /* 30*596Sbill * Flags settable from the argv process argument list 31*596Sbill */ 32*596Sbill int silent = 0; /*don't complain about any errors*/ 33*596Sbill int savelabels = 0; /*write the labels to the a.out file*/ 34*596Sbill int d124 = 4; /*default allocate 4 bytes for unknown pointers*/ 35*596Sbill int anyerrs = 0; /*no errors yet*/ 36*596Sbill int orgwarn = 0; /*Bad origins*/ 37*596Sbill int passno = 1; /* current pass*/ 38*596Sbill 39*596Sbill #ifdef DEBUG 40*596Sbill int debug = 0; 41*596Sbill int toktrace = 0; 42*596Sbill #endif 43*596Sbill 44*596Sbill int useVM = /*put the temp file in virtual memory*/ 45*596Sbill #ifdef VMS 46*596Sbill 1; /*VMS has virtual memory (duh)*/ 47*596Sbill #endif VMS 48*596Sbill #ifdef UNIX 49*596Sbill 0; 50*596Sbill #endif 51*596Sbill 52*596Sbill char *endcore; /*where to get more symbol space*/ 53*596Sbill 54*596Sbill /* 55*596Sbill * Managers of the a.out file. 56*596Sbill */ 57*596Sbill struct exec hdr; 58*596Sbill #define MAGIC 0410 59*596Sbill u_long tsize; /* total text size */ 60*596Sbill u_long dsize; /* total data size */ 61*596Sbill u_long datbase; /* base of the data segment */ 62*596Sbill u_long trsize; /* total text relocation size */ 63*596Sbill u_long drsize; /* total data relocation size */ 64*596Sbill 65*596Sbill /* 66*596Sbill * Information about the current segment is accumulated in 67*596Sbill * usedot; the most important information stored is the 68*596Sbill * accumulated size of each of the text and data segments 69*596Sbill * 70*596Sbill * dotp points to the correct usedot expression for the current segment 71*596Sbill */ 72*596Sbill struct exp usedot[NLOC+NLOC]; /* info about all segments */ 73*596Sbill struct exp *dotp; /* data/text location pointer */ 74*596Sbill /* 75*596Sbill * The inter pass temporary file is opened and closed by stdio, but 76*596Sbill * is written to using direct read/write, as the temporary file 77*596Sbill * is composed of buffers exactly BUFSIZ long. 78*596Sbill */ 79*596Sbill FILE *tmpfil; /* interpass communication file */ 80*596Sbill /* 81*596Sbill * a.out is created during the second pass. 82*596Sbill * It is opened by stdio, but is filled with the parallel 83*596Sbill * block I/O library 84*596Sbill */ 85*596Sbill char *outfile = "a.out"; 86*596Sbill FILE *a_out_file; 87*596Sbill off_t a_out_off; /* cumulative offsets for segments */ 88*596Sbill /* 89*596Sbill * The logical files containing the assembled data for each of 90*596Sbill * the text and data segments are 91*596Sbill * managed by the parallel block I/O library. 92*596Sbill * a.out is logically opened in many places at once to 93*596Sbill * receive the assembled data from the various segments as 94*596Sbill * it all trickles in, but is physically opened only once 95*596Sbill * to minimize file overhead. 96*596Sbill */ 97*596Sbill BFILE *usefile[NLOC+NLOC]; /* text/data files */ 98*596Sbill BFILE *txtfil; /* current text/data file */ 99*596Sbill /* 100*596Sbill * Relocation information is accumulated seperately for each 101*596Sbill * segment. This is required by the old loader (from BTL), 102*596Sbill * but not by the new loader (Bill Joy). 103*596Sbill * 104*596Sbill * However, the size of the relocation information can not be computed 105*596Sbill * during or after the 1st pass because the ''absoluteness' of values 106*596Sbill * is unknown until all locally declared symbols have been seen. 107*596Sbill * Thus, the size of the relocation information is only 108*596Sbill * known after the second pass is finished. 109*596Sbill * This obviates the use of the block I/O 110*596Sbill * library, which requires knowing the exact offsets in a.out. 111*596Sbill * 112*596Sbill * So, we save the relocation information internally (we don't 113*596Sbill * go to internal files to minimize overhead). 114*596Sbill * 115*596Sbill * Empirically, we studied 259 files composing the system, 116*596Sbill * two compilers and a compiler generator: (all of which have 117*596Sbill * fairly large source files) 118*596Sbill * 119*596Sbill * Number of files = 259 120*596Sbill * Number of non zero text reloc files: 233 121*596Sbill * Number of non zero data reloc files: 53 122*596Sbill * Average text relocation = 889 123*596Sbill * Average data relocation = 346 124*596Sbill * Number of files > BUFSIZ text relocation = 71 125*596Sbill * Number of files > BUFSIZ data relocation = 6 126*596Sbill * 127*596Sbill * For compiled C code, there is usually one text segment and two 128*596Sbill * data segments; we see that allocating our own buffers and 129*596Sbill * doing our internal handling of relocation information will, 130*596Sbill * on the average, not use more memory than taken up by the buffers 131*596Sbill * allocated for doing file I/O in parallel to a number of file. 132*596Sbill * 133*596Sbill * If we are assembling with the -V option, we 134*596Sbill * use the left over token buffers from the 2nd pass, 135*596Sbill * otherwise, we create our own. 136*596Sbill * 137*596Sbill * When the 2nd pass is complete, closeoutrel flushes the token 138*596Sbill * buffers out to a BFILE. 139*596Sbill * 140*596Sbill * The internals to relbufdesc are known only in assyms.c 141*596Sbill * 142*596Sbill * outrel constructs the relocation information. 143*596Sbill * closeoutrel flushes the relocation information to relfil. 144*596Sbill */ 145*596Sbill struct relbufdesc *rusefile[NLOC+NLOC]; 146*596Sbill struct relbufdesc *relfil; /* un concatnated relocation info */ 147*596Sbill BFILE *relocfile; /* concatnated relocation info */ 148*596Sbill /* 149*596Sbill * Once the relocation information has been written, 150*596Sbill * we can write out the symbol table using the Block I/O 151*596Sbill * mechanisms, as we once again know the offsets into 152*596Sbill * the a.out file. 153*596Sbill * 154*596Sbill * We use relfil to output the symbol table information. 155*596Sbill */ 156*596Sbill 157*596Sbill char *tmpdirprefix = 158*596Sbill #ifdef UNIX 159*596Sbill "/tmp/"; 160*596Sbill #else VMS 161*596Sbill "/usr/tmp/"; 162*596Sbill #endif 163*596Sbill 164*596Sbill #define TMP_SUFFIX "asXXXXXX" 165*596Sbill char tmpn1[TNAMESIZE]; 166*596Sbill 167*596Sbill int delexit(); 168*596Sbill 169*596Sbill main(argc, argv) 170*596Sbill int argc; 171*596Sbill char **argv; 172*596Sbill { 173*596Sbill 174*596Sbill tmpn1[0] = 0; 175*596Sbill endcore = (char *)sbrk(0); 176*596Sbill 177*596Sbill argprocess(argc, argv); /* process argument lists */ 178*596Sbill if (anyerrs) exit(1); 179*596Sbill 180*596Sbill initialize(); 181*596Sbill zeroorigins(); /* set origins to zero */ 182*596Sbill zerolocals(); /* fix local label counters */ 183*596Sbill 184*596Sbill i_pass1(); /* open temp files, etc */ 185*596Sbill pass1(); /* first pass through .s files */ 186*596Sbill testlocals(); /* check for undefined locals */ 187*596Sbill if (anyerrs) delexit(); 188*596Sbill 189*596Sbill pass1_5(); /* resolve jxxx */ 190*596Sbill if (anyerrs) delexit(); 191*596Sbill 192*596Sbill open_a_out(); /* open a.out */ 193*596Sbill roundsegments(); /* round segments to FW */ 194*596Sbill build_hdr(); /* build initial header, and output */ 195*596Sbill 196*596Sbill i_pass2(); /* reopen temporary file, etc */ 197*596Sbill pass2(); /* second pass through the virtual .s */ 198*596Sbill if (anyerrs) delexit(); 199*596Sbill 200*596Sbill fillsegments(); /* fill segments with 0 to FW */ 201*596Sbill reloc_syms(); /* dump relocation and symbol table */ 202*596Sbill 203*596Sbill delete(); /* remove tmp file */ 204*596Sbill bflush(); /* close off block I/O view of a.out */ 205*596Sbill fix_a_out(); /* add in text and data reloc counts */ 206*596Sbill 207*596Sbill if (anyerrs == 0 && orgwarn) 208*596Sbill yyerror("Caution: absolute origins.\n"); 209*596Sbill exit(anyerrs != 0); 210*596Sbill } /*end of UNIX main*/ 211*596Sbill 212*596Sbill argprocess(argc, argv) 213*596Sbill int argc; 214*596Sbill char *argv[]; 215*596Sbill { 216*596Sbill register char *cp; 217*596Sbill 218*596Sbill ninfiles = 0; 219*596Sbill silent = 0; 220*596Sbill #ifdef DEBUG 221*596Sbill debug = 0; 222*596Sbill #endif 223*596Sbill dotsname = "<argv error>"; 224*596Sbill while (argc > 1) { 225*596Sbill if (argv[1][0] == '-'){ 226*596Sbill cp = argv[1] + 1; 227*596Sbill /* 228*596Sbill * We can throw away single minus signs, so 229*596Sbill * that make scripts for the PDP 11 assembler work 230*596Sbill * on this assembler too 231*596Sbill */ 232*596Sbill while (*cp){ 233*596Sbill switch(*cp++){ 234*596Sbill default: 235*596Sbill yyerror("Unknown flag: %c", *--cp); 236*596Sbill cp++; 237*596Sbill break; 238*596Sbill case 'd': 239*596Sbill d124 = *cp++ - '0'; 240*596Sbill if ( (d124 != 1) && (d124 != 2) && 241*596Sbill (d124 != 4)){ 242*596Sbill yyerror("-d[124] only"); 243*596Sbill exit(1); 244*596Sbill } 245*596Sbill break; 246*596Sbill case 'o': 247*596Sbill if (argc < 3){ 248*596Sbill yyerror("-o what???"); 249*596Sbill exit(1); 250*596Sbill } 251*596Sbill outfile = argv[2]; 252*596Sbill bumpone: 253*596Sbill argc -= 2; 254*596Sbill argv += 2; 255*596Sbill goto nextarg; 256*596Sbill 257*596Sbill case 't': 258*596Sbill if (argc < 3){ 259*596Sbill yyerror("-t what???"); 260*596Sbill exit(1); 261*596Sbill } 262*596Sbill tmpdirprefix = argv[2]; 263*596Sbill goto bumpone; 264*596Sbill 265*596Sbill case 'V': 266*596Sbill useVM = 1; 267*596Sbill break; 268*596Sbill case 'W': 269*596Sbill silent = 1; 270*596Sbill break; 271*596Sbill case 'L': 272*596Sbill savelabels = 1; 273*596Sbill break; 274*596Sbill #ifdef DEBUG 275*596Sbill case 'D': 276*596Sbill debug = 1; 277*596Sbill break; 278*596Sbill case 'T': 279*596Sbill toktrace = 1; 280*596Sbill break; 281*596Sbill #endif 282*596Sbill } /*end of the switch*/ 283*596Sbill } /*end of pulling out all arguments*/ 284*596Sbill } /*end of a flag argument*/ 285*596Sbill else { /*file name*/ 286*596Sbill if (ninfiles > 32){ 287*596Sbill yyerror("More than 32 file names"); 288*596Sbill exit(3); 289*596Sbill } 290*596Sbill innames[ninfiles++] = argv[1]; 291*596Sbill } 292*596Sbill --argc; ++argv; 293*596Sbill nextarg:; 294*596Sbill } 295*596Sbill } 296*596Sbill 297*596Sbill initialize() 298*596Sbill { 299*596Sbill if (signal(SIGINT, SIG_IGN) != SIG_IGN) 300*596Sbill signal(SIGINT, delexit); 301*596Sbill /* 302*596Sbill * Install symbols in the table 303*596Sbill */ 304*596Sbill symtabinit(); 305*596Sbill syminstall(); 306*596Sbill /* 307*596Sbill * Build the expression parser accelerator token sets 308*596Sbill */ 309*596Sbill buildtokensets(); 310*596Sbill } 311*596Sbill 312*596Sbill zeroorigins() 313*596Sbill { 314*596Sbill register int locindex; 315*596Sbill /* 316*596Sbill * Mark usedot: the first NLOC slots are for named text segments, 317*596Sbill * the next for named data segments. 318*596Sbill */ 319*596Sbill for (locindex = 0; locindex < NLOC; locindex++){ 320*596Sbill usedot[locindex].xtype = XTEXT; 321*596Sbill usedot[NLOC + locindex].xtype = XDATA; 322*596Sbill usedot[locindex].xvalue = 0; 323*596Sbill usedot[NLOC + locindex].xvalue = 0; 324*596Sbill usedot[locindex].yvalue = 0; 325*596Sbill usedot[NLOC + locindex].yvalue = 0; 326*596Sbill } 327*596Sbill } 328*596Sbill 329*596Sbill zerolocals() 330*596Sbill { 331*596Sbill register int i; 332*596Sbill 333*596Sbill for (i = 0; i <= 9; i++) { 334*596Sbill lgensym[i] = 1; 335*596Sbill genref[i] = 0; 336*596Sbill } 337*596Sbill } 338*596Sbill 339*596Sbill i_pass1() 340*596Sbill { 341*596Sbill if (useVM == 0){ 342*596Sbill strcat(tmpn1, tmpdirprefix); 343*596Sbill strcat(tmpn1, TMP_SUFFIX); 344*596Sbill mktemp(tmpn1); 345*596Sbill tmpfil = fopen(tmpn1, "w"); 346*596Sbill if (tmpfil==NULL) { 347*596Sbill yyerror("Bad pass 1 temporary file for writing %s", tmpn1); 348*596Sbill delexit(); 349*596Sbill } 350*596Sbill } 351*596Sbill 352*596Sbill inittmpfile(); 353*596Sbill } 354*596Sbill 355*596Sbill pass1() 356*596Sbill { 357*596Sbill register int i; 358*596Sbill 359*596Sbill passno = 1; 360*596Sbill dotp = &usedot[0]; 361*596Sbill txtfil = (BFILE *)0; 362*596Sbill relfil = (struct relbufdesc *)0; 363*596Sbill 364*596Sbill if (ninfiles == 0){ /*take the input from stdin directly*/ 365*596Sbill lineno = 1; 366*596Sbill dotsname = "<stdin>"; 367*596Sbill 368*596Sbill yyparse(); 369*596Sbill } else { /*we have the names tanked*/ 370*596Sbill for (i = 0; i < ninfiles; i++){ 371*596Sbill new_dot_s(innames[i]); 372*596Sbill if (freopen(innames[i], "r", stdin) == NULL) { 373*596Sbill yyerror( "Can't open source file %s\n", 374*596Sbill innames[i]); 375*596Sbill exit(2); 376*596Sbill } 377*596Sbill /* stdio is NOT used to read the input characters */ 378*596Sbill /* we use read directly, into our own buffers */ 379*596Sbill yyparse(); 380*596Sbill } 381*596Sbill } 382*596Sbill 383*596Sbill closetmpfile(); /*kick out the last buffered intermediate text*/ 384*596Sbill } 385*596Sbill 386*596Sbill testlocals() 387*596Sbill { 388*596Sbill register int i; 389*596Sbill for (i = 0; i <= 9; i++) { 390*596Sbill if (genref[i]) 391*596Sbill yyerror("Reference to undefined local label %df", i); 392*596Sbill lgensym[i] = 1; 393*596Sbill genref[i] = 0; 394*596Sbill } 395*596Sbill } 396*596Sbill 397*596Sbill pass1_5() 398*596Sbill { 399*596Sbill sortsymtab(); 400*596Sbill #ifdef DEBUG 401*596Sbill if (debug) dumpsymtab(); 402*596Sbill #endif 403*596Sbill jxxxfix(); 404*596Sbill #ifdef DEBUG 405*596Sbill if (debug) dumpsymtab(); 406*596Sbill #endif 407*596Sbill } 408*596Sbill 409*596Sbill open_a_out() 410*596Sbill { 411*596Sbill /* 412*596Sbill * Open up the a.out file now, and get set to build 413*596Sbill * up offsets into it for all of the various text,data 414*596Sbill * text relocation and data relocation segments. 415*596Sbill */ 416*596Sbill a_out_file = fopen(outfile, "w"); 417*596Sbill if (a_out_file == NULL) { 418*596Sbill yyerror("Cannot create %s", outfile); 419*596Sbill delexit(); 420*596Sbill } 421*596Sbill biofd = a_out_file->_file; 422*596Sbill a_out_off = 0; 423*596Sbill } 424*596Sbill 425*596Sbill roundsegments() 426*596Sbill { 427*596Sbill register int locindex; 428*596Sbill register long v; 429*596Sbill /* 430*596Sbill * round and assign text segment origins 431*596Sbill * the exec header always goes in usefile[0] 432*596Sbill */ 433*596Sbill tsize = 0; 434*596Sbill for (locindex=0; locindex<NLOC; locindex++) { 435*596Sbill v = round(usedot[locindex].xvalue, FW); 436*596Sbill usedot[locindex].xvalue = tsize; 437*596Sbill if ((locindex == 0) || (v != 0) ){ 438*596Sbill usefile[locindex] = (BFILE *)Calloc(1, sizeof(BFILE)); 439*596Sbill bopen(usefile[locindex], a_out_off); 440*596Sbill if (locindex == 0) 441*596Sbill a_out_off = sizeof (struct exec); 442*596Sbill } else { 443*596Sbill usefile[locindex] = (BFILE *)-1; 444*596Sbill } 445*596Sbill tsize += v; 446*596Sbill a_out_off += v; 447*596Sbill } 448*596Sbill /* 449*596Sbill * Round and assign data segment origins. 450*596Sbill */ 451*596Sbill datbase = round(tsize, PAGRND); 452*596Sbill for (locindex=0; locindex<NLOC; locindex++) { 453*596Sbill v = round(usedot[NLOC+locindex].xvalue, FW); 454*596Sbill usedot[NLOC+locindex].xvalue = datbase + dsize; 455*596Sbill if (v != 0){ 456*596Sbill usefile[NLOC + locindex] = (BFILE *)Calloc(1,sizeof(BFILE)); 457*596Sbill bopen(usefile[NLOC + locindex], a_out_off); 458*596Sbill } else { 459*596Sbill usefile[NLOC + locindex] = (BFILE *)-1; 460*596Sbill } 461*596Sbill dsize += v; 462*596Sbill a_out_off += v; 463*596Sbill } 464*596Sbill /* 465*596Sbill * Assign final values to symbols 466*596Sbill */ 467*596Sbill hdr.a_bss = dsize; 468*596Sbill freezesymtab(); /* this touches hdr.a_bss */ 469*596Sbill stabfix(); 470*596Sbill /* 471*596Sbill * Set up the relocation information "files" to 472*596Sbill * be zero; outrel takes care of the rest 473*596Sbill */ 474*596Sbill for (locindex = 0; locindex < NLOC + NLOC; locindex++){ 475*596Sbill rusefile[locindex] = (struct relbufdesc *)0; 476*596Sbill } 477*596Sbill } 478*596Sbill 479*596Sbill build_hdr() 480*596Sbill { 481*596Sbill /* 482*596Sbill * Except for the text and data relocation sizes, 483*596Sbill * calculate the final values for the header 484*596Sbill * 485*596Sbill * Write out the initial copy; we to come 486*596Sbill * back later and patch up a_trsize and a_drsize, 487*596Sbill * and overwrite this first version of the header. 488*596Sbill */ 489*596Sbill hdr.a_magic = MAGIC; 490*596Sbill hdr.a_text = tsize; 491*596Sbill hdr.a_data = dsize; 492*596Sbill hdr.a_bss -= dsize; 493*596Sbill hdr.a_syms = sizesymtab(); /* Does not include string pool length */ 494*596Sbill hdr.a_entry = 0; 495*596Sbill hdr.a_trsize = 0; 496*596Sbill hdr.a_drsize = 0; 497*596Sbill 498*596Sbill bwrite((char *)&hdr, sizeof(hdr), usefile[0]); 499*596Sbill } 500*596Sbill 501*596Sbill i_pass2() 502*596Sbill { 503*596Sbill if (useVM == 0) { 504*596Sbill fclose(tmpfil); 505*596Sbill tmpfil = fopen(tmpn1, "r"); 506*596Sbill if (tmpfil==NULL) { 507*596Sbill yyerror("Bad pass 2 temporary file for reading %s", tmpn1); 508*596Sbill delexit(); 509*596Sbill } 510*596Sbill } 511*596Sbill } 512*596Sbill 513*596Sbill pass2() 514*596Sbill { 515*596Sbill #ifdef DEBUG 516*596Sbill if (debug) 517*596Sbill printf("\n\n\n\t\tPASS 2\n\n\n\n"); 518*596Sbill #endif DEBUG 519*596Sbill passno = 2; 520*596Sbill lineno = 1; 521*596Sbill dotp = &usedot[0]; 522*596Sbill txtfil = usefile[0]; /* already opened (always!) */ 523*596Sbill relfil = 0; /* outrel takes care of the rest */ 524*596Sbill initoutrel(); 525*596Sbill 526*596Sbill inittmpfile(); 527*596Sbill 528*596Sbill yyparse(); 529*596Sbill 530*596Sbill closetmpfile(); 531*596Sbill } 532*596Sbill 533*596Sbill fillsegments() 534*596Sbill { 535*596Sbill int locindex; 536*596Sbill /* 537*596Sbill * Round text and data segments to FW by appending zeros 538*596Sbill */ 539*596Sbill for (locindex = 0; locindex < NLOC + NLOC; locindex++) { 540*596Sbill if (usefile[locindex]) { 541*596Sbill txtfil = usefile[locindex]; 542*596Sbill dotp = &usedot[locindex]; 543*596Sbill while (usedot[locindex].xvalue & FW) 544*596Sbill outb(0); 545*596Sbill } 546*596Sbill } 547*596Sbill } 548*596Sbill 549*596Sbill reloc_syms() 550*596Sbill { 551*596Sbill u_long closerelfil(); 552*596Sbill /* 553*596Sbill * Move the relocation information to a.out 554*596Sbill * a_out_off is the offset so far: 555*596Sbill * exec + text segments + data segments 556*596Sbill */ 557*596Sbill relocfile = (BFILE *)Calloc(1,sizeof(BFILE)); 558*596Sbill bopen(relocfile, a_out_off); 559*596Sbill a_out_off += closeoutrel(relocfile); 560*596Sbill 561*596Sbill hdr.a_trsize = trsize; 562*596Sbill hdr.a_drsize = drsize; 563*596Sbill /* 564*596Sbill * Output the symbol table 565*596Sbill * and if FLEXNAMES is set, the string pool 566*596Sbill */ 567*596Sbill symwrite(relocfile); 568*596Sbill } 569*596Sbill 570*596Sbill fix_a_out() 571*596Sbill { 572*596Sbill if (lseek(a_out_file->_file, 0L, 0) < 0) 573*596Sbill yyerror("Reposition for header rewrite fails"); 574*596Sbill if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0) 575*596Sbill yyerror("Rewrite of header fails"); 576*596Sbill } 577*596Sbill 578*596Sbill delexit() 579*596Sbill { 580*596Sbill delete(); 581*596Sbill if (passno == 2){ 582*596Sbill unlink(outfile); 583*596Sbill } 584*596Sbill exit(1); 585*596Sbill } 586*596Sbill 587*596Sbill delete() 588*596Sbill { 589*596Sbill if (useVM == 0 || tmpn1[0]) 590*596Sbill unlink(tmpn1); 591*596Sbill } 592*596Sbill 593*596Sbill sawabort() 594*596Sbill { 595*596Sbill char *fillinbuffer(); 596*596Sbill while (fillinbuffer() != (char *)0) 597*596Sbill continue; 598*596Sbill delete(); 599*596Sbill exit(1); /*although the previous pass will also exit non zero*/ 600*596Sbill } 601*596Sbill 602*596Sbill panic(fmt, a1, a2, a3, a4) 603*596Sbill char *fmt; 604*596Sbill /*VARARGS 1*/ 605*596Sbill { 606*596Sbill yyerror("Assembler panic: bad internal data structure."); 607*596Sbill yyerror(fmt, a1, a2, a3, a4); 608*596Sbill delete(); 609*596Sbill abort(); 610*596Sbill } 611