Source code for /engineering/bos/BOA.COriginal file BOA.C
   1 /*
   2 	BattleOS : Engage battling programs.
   3 
   4 	Copyright (C) 1992 Erich P Gatejen    ALL RIGHTS RESERVED
   5 
   6 
   7 	File     : BOA.C
   8 	Purpose  : Program code for the BattleOS Assembler
   9 
  10 */
  11 
  12 
  13 /* ---- INCLUDE files ------------------------------------------------*/
  14 
  15 #include<stdio.h>
  16 #include<conio.h>
  17 #include<alloc.h>
  18 #include "boa.h"
  19 #include "bos.h"
  20 
  21 /* ---- Global Variables --------------------------------------------*/
  22 
  23    FILE	 		*InFile;
  24    FILE        	*OutFile;		/* File for input and output */
  25    FILE			*ListF;		/* For a list file		    */
  26 
  27    Taunt       	Taunts[TAUNTSNUMBER];    /* Taunt arrays    */
  28    char			ProgName[PROGNAMESIZE];  /* Program name    */
  29 
  30    unsigned int     LineCount  = 1; /* Line being processed	     */
  31    unsigned int     InstrCount = 0; /* Instruction counter       */
  32 
  33    unsigned int	ErrorCount = 0; /* Number of errors encountered */
  34 
  35    /* Boolean variables */
  36    char			HaveProgName = FALSE;  /* Does a program name exist? */
  37 
  38    /* Pointer to label chain */
  39    struct Label	*FirstLabel  = NULL;   /* Insure no labels in list   */
  40 
  41    /* Output file name */
  42    char	  FileOut[14];
  43 
  44    /* List file name */
  45    char	  ListOut[14];
  46 
  47    /* Flag the use of a list file */
  48    char	  ListFile = FALSE;	
  49 
  50    /* Flag PassTwo is underway */
  51    char	  PassTwoF = FALSE;
  52 
  53    /* Put these instr generation vars here to uncomplicate things */
  54    int	  Operand1;
  55    int	  Operand2;
  56    unsigned char    OperandType1;
  57    unsigned char	OperandType2;
  58 
  59    /* Taunt usage list */
  60    char	  TauntUsage[8]  = { FALSE, FALSE, FALSE, FALSE, FALSE, 
  61 						 FALSE, FALSE, FALSE			 }; 
  62 
  63    /* Instruction count for list file */
  64    unsigned int	  InstrPut;
  65 
  66    /* Instruction binary, for list file */
  67    char	  InstrBinary[15];
  68 
  69 
  70 /* --- Messages to the user ----------------------------------------*/
  71 
  72 void Do_Opening() {
  73 
  74 	cputs("\n\r");
  75 	cputs(" !! Battle Operating System !!  (C) 1993 Erich P Gatejen\n\r");
  76 	cputs(" Battle Operating system Assembler ( BOA ) v1.0 -\n\r\n\r");
  77 
  78 }; /* end Do_Opening */
  79 
  80 
  81 void Message_No_File() {
  82 
  83 	cputs(" -ERROR:  No filename specified for processing.\n\r\n\r");
  84 
  85 }; /* end Message_No_File */
  86 
  87 
  88 void Message_Bye() {
  89 
  90 	cputs(" --- BASM completed  \n\r\n\r");
  91 
  92 };
  93 
  94 void Message_Cant_Open( char   *Name ) {
  95 
  96 	printf(" -ERROR:  Cannot open file '%s'.\n\r\n\r", Name );
  97 
  98 };
  99 
 100 void Message_Bad_File_Name() {
 101 
 102 	cputs("  -ERROR:  Cannot use filename.\n\r\n\r");
 103 
 104 };
 105 
 106 void Message_ASM_Abort() {
 107 
 108 	printf("\n\r - %d errors encountered.\n\r", ErrorCount );
 109 	cputs( " !ABORTING assembly!\n\r\n\r");
 110 
 111 }; /* end PassOne */
 112 
 113 void Error_Message( char *String ) {
 114 
 115 	printf(" --- Error - line %d :", LineCount );
 116 	printf(" %s\n\r", String );
 117 	ErrorCount++;
 118 
 119 	/* Put in list file if enabled */
 120 	if ( ListFile == TRUE ) {
 121 
 122 	/* if PassTwo error, then write a CR/LF */
 123 	if ( PassTwoF == TRUE ) fputs("\n\r", ListF );
 124 
 125 	fprintf( ListF, "  --- Error - line %d :", LineCount );
 126 	fprintf( ListF, "  %s\n\r", String );
 127         
 128 	}; /* end if */
 129 
 130 }; /* end Error_Message */
 131 
 132 
 133 /* --- Routines ----------------------------------------------------*/
 134 
 135 /* -------- OpenFiles routine. ---------- */
 136 int OpenFiles( char	  *FileName ) {
 137 
 138 	int    FindExt;
 139 
 140 	/* Open file, if good open output, else message error  */
 141 	if ((InFile = fopen( FileName, "rt" )) == NULL) {
 142 	   Message_Cant_Open( FileName );
 143 	   return( 1 );			/* Return nonzero */
 144 	};
 145 
 146  /* Parse file name, change extention, and open it for output */
 147 	strcpy( FileOut, FileName );
 148 
 149 	/* Find the extension */
 150 	FindExt = 0;
 151 	while ((FileOut[FindExt] != '.') && (FileOut[FindExt] != NULL)) {
 152 	   FindExt++;
 153 	};
 154 
 155 	/* See if this file name is haywire */
 156 	if (FindExt > 8) {
 157 		Message_Bad_File_Name();
 158 		return( 1 );
 159 	};
 160 
 161 
 162 	if (FileOut[FindExt] == NULL) FileOut[FindExt] = '.';
 163 
 164 	/* Add the extension */
 165 	FindExt++;
 166 
 167 	FileOut[FindExt] 	= 'B';
 168 	FileOut[FindExt+1]  = 'O';
 169 	FileOut[FindExt+2]  = 'S';
 170 	FileOut[FindExt+3]  = NULL;
 171 
 172 	/* Open output file if we can, else error */
 173 	if ((OutFile = fopen(FileOut, "wb")) == NULL) {
 174 	   Message_Cant_Open( FileOut );
 175 	   return( 1 );			/* Return nonzero */
 176 	};
 177 
 178 	return( NULL );  /* Return SUCCESS! */
 179 
 180 }; /* end OpenFiles */
 181 
 182 
 183 /* -------- OpenList routine. ---------- */
 184 int OpenList( char	  *FileName ) {
 185 
 186 	int    FindExt;
 187 
 188 	/* Open file, if good open output, else message error  */
 189 	if ((ListF = fopen( FileName, "wb" )) == NULL) {
 190 	   Message_Cant_Open( FileName );
 191 	   return( FALSE );			/* Return nonzero */
 192 	};
 193 
 194 	return( TRUE );  /* Return SUCCESS! */
 195 
 196 }; /* end OpenList */
 197 
 198 /* -------- ListFileTail --------------- */
 199 void  ListFileTail () {
 200 
 201    /* Jump down a few lines */
 202    fputs("\n\r\n\r", ListF );
 203 
 204    /* Put general info */
 205    fputs("-- End assembly.\n\r", ListF );
 206 
 207    /* List number of errors found */
 208    fprintf( ListF, " - Number of errors : %d\n\r\n\r", ErrorCount );
 209 
 210    /* If it made it to pass two, then do label list */
 211    if  ( PassTwoF == TRUE ) {
 212 
 213 	 /* Label list header */
 214 	 fputs("--- Label List ---------------\n\r", ListF );
 215 
 216       /* use FirstLabel pointer to traverse.  ( it's not needed anymore ) */
 217 	 while ( FirstLabel != NULL ) {
 218 
 219 	    fprintf( ListF,            "%-10s = %04d \n\r",
 220 			   FirstLabel->Text, FirstLabel->Offset );
 221 
 222 	    /* Move to next label */
 223          FirstLabel = FirstLabel->Next;
 224 
 225       }; /* end while */
 226 
 227    }; /* end if */
 228 
 229 }; /* end ListFileTail */
 230 
 231 
 232 /* -------- CloseFiles routine --------- */
 233 void  CloseFiles () {
 234 
 235 	fclose( InFile  );
 236 	fclose( OutFile );
 237 
 238 	/* If there was a list file, then close it */
 239 	if ( ListFile == TRUE ) {
 240 
 241 	   ListFileTail();
 242 	   fclose( ListF );
 243 
 244      }; /* end if */
 245 
 246 }; /* end CloseFiles */
 247 
 248 
 249 /* -------- CloseFilesK routine --------- */
 250 void  CloseFilesK () {
 251 
 252 	fclose( InFile  );
 253 	fclose( OutFile );
 254 
 255 	/* Kill the output file */
 256 	unlink( FileOut );
 257 
 258 	/* If there was a list file, then close it */
 259 	if ( ListFile == TRUE ) {
 260 
 261         ListFileTail();
 262 	   fclose( ListF );
 263 
 264      }; /* end if */
 265 
 266 }; /* end CloseFiles */
 267 
 268 
 269 /* --------- Get the program name --------- */
 270 void  Get_Prog_Name ( char  *String ) {
 271 
 272 	int  Step = 0;
 273 
 274 
 275 	/* Check if a program name has already been declared 		*/
 276 	if ( HaveProgName == TRUE ) {
 277 	   /* Message error and return 						*/
 278 	   Error_Message("Multipul program names" );
 279 	   return;
 280 	};
 281 
 282 	String++;   /* Move to first char				    */
 283 
 284 	/* Move program name and set HaveProgName flag	    */
 285 	while ( (*String != '\n')&&( Step != PROGNAMESIZE ) ) {
 286 	   ProgName[Step] = *String;
 287 	   Step++;
 288 	   String++;
 289 	};
 290 
 291      HaveProgName = TRUE;   /* We now have a program name! */
 292 
 293 }; /* end Get_Prog_Name */
 294 
 295 
 296 /* ----------- CheckMnemonic --------------*/
 297 int  CheckMnemonic ( char  *String ) {
 298 
 299    int	Step;
 300    char   Mnemonic[4];
 301 
 302 
 303    for ( Step=0; Step<3; Step++) {
 304 
 305 	 Mnemonic[Step] = *String;
 306 	 String++;
 307 
 308    }; /* end for */
 309    Mnemonic[3] = NULL;
 310 
 311    /* Adjust TAB or CR to space */
 312    if ((Mnemonic[2] == 9)||(Mnemonic[2] == '\n')) Mnemonic[2] = ' ';
 313 
 314    /* Insure lower case	 */
 315    strlwr( Mnemonic );
 316 
 317    /* Pad space, if neccessary, for 2 letter mnemonics */
 318    if (Mnemonic[2] == '\n') Mnemonic[2] = ' ';
 319 
 320    /* Find Token */
 321    Step = 0;
 322    while( strcmp( TokenTable[Step].Text, Mnemonic) != 0 ) {
 323 
 324 	 Step++;
 325 
 326 	 /* If step == number of tokens then the mnemonic is not recognized */
 327 	 if ( Step == Numtokens ) {
 328 
 329      	Error_Message( "Unknown mnemonic!" );
 330 		return( BADMNEMONIC );
 331 
 332 	 }; /* end if */
 333 
 334    }; /* end while */
 335 
 336    /* return position in token table */
 337    return( Step );
 338 
 339 
 340 }; /* end CheckMnemonic */
 341 
 342 
 343 /* ----------- Set_Taunt ----------------*/
 344 void  Set_Taunt( char  *String ) {
 345 
 346 	int		TauntNum;
 347 	char		NumChar;
 348 	int		Step		= 0;
 349 
 350   /* Get taunt number */
 351 	String++;				/* Point to number */
 352 	NumChar  = *String;
 353      String++;
 354 
 355 	/* Check number validity */
 356 	if ( (NumChar < '0')||(NumChar > '7')||(*String != '"') ) {
 357 		/* Invalid, message and return */
 358 		Error_Message( "Invalid taunt format.");
 359 		return;
 360 		};
 361 
 362 	/* Set TauntNum */
 363 	TauntNum = NumChar - '0';
 364 
 365 	/* See if the taunt is in use, if so ERROR */
 366 	if ( TauntUsage[TauntNum] == TRUE ) {
 367 
 368 	   Error_Message("Taunt number already used.");
 369 	   return;
 370 
 371 	}; /* end if */
 372 
 373 	/* Set the taunt number as in use */
 374 	TauntUsage[TauntNum] = TRUE;
 375 
 376   /* Move taunt text */
 377 	String++;				/* Point to beginning of text */
 378 	while( (*String != '\n')&&(Step < TAUNTSIZE) ) {
 379 		Taunts[TauntNum][Step] = *String;
 380 		String++;
 381           Step++;
 382 	};
 383 
 384 	/* Done */
 385 
 386 }; /* end Set_Taunt */
 387 
 388 
 389 /* ----------- Get_Value ------------------*/
 390 int  Get_Value ( char *String, int *Value ) {
 391 
 392 	char		Buffer[6];
 393 	long 	Number;
 394 	int		Step;
 395 	int		SignValue;
 396 
 397 
 398      Step = 0;
 399 
 400 	/* Check for data, error if data not flush with indicator (+,#,or $) */
 401 	if ( (*String == ' ')||(*String == '\t')||(*String =='\n')||
 402 	    ( (*String <  '0')&&(*String > '9')&&(*String != '+')&&
 403 		 (*String != '-') )                                    ) {
 404 
 405 	   /* Error */
 406 	   Error_Message("Incorrect data format");
 407         return( FALSE );
 408 
 409 	}; /* end if */
 410 
 411 
 412 	/* Check for a negative sign */
 413 	if ( *String == '-' ) {
 414 
 415 	   SignValue = -1;
 416 	   String++;		/* Move beyond sign character */
 417 	   }
 418 	else
 419 	   SignValue = 1;
 420 
 421 	/* If there is a '+', suck it up */
 422 	if ( *String == '+' ) ++String;
 423 
 424 	/* Stuff the buffer */
 425 	while( (*String >= '0') && (*String <= '9') ) {
 426 
 427 	   /* See if number is automatically to large ( in char size ) */
 428 	   if ( Step == 5 ) {
 429 
 430 		 /* if so, report the error, and return */
 431 		 Error_Message( "Data item to large." );
 432 		 return( FALSE );
 433 
 434 	   };
 435 
 436 	   Buffer[Step] = *String;
 437 	   Step++;
 438 	   String++;
 439 	};
 440 
 441 	/* Null terminate the string */
 442 	Buffer[Step] = NULL;
 443 
 444      /* Translate to long int     */
 445 	Number = atol( Buffer );
 446 
 447 	/* Sign the number		    */
 448 	Number = Number * SignValue;
 449 
 450 	/* See if the number is outside a sign int range, if so then error */
 451 	if ( (Number > INTHI ) || (Number < INTLOW) )  return( FALSE );
 452 
 453 	/* Stuff into Value and return good */
 454 	*Value = Number;
 455      return( TRUE );
 456 
 457 
 458 }; /* end Get_Value */
 459 
 460 
 461 /* ----------- Find_More ------------------*/
 462 void  Find_More ( char  *String ) {
 463 
 464 	int   Step;
 465 
 466 
 467 	/* Find the next non space character of the line ( or no character ) */
 468 	while ( (*String == 32)||(*String == 9) ) {
 469 	   String++;
 470 	};
 471                               /*  Tab char ^   */
 472 	/* case through possibilities */
 473 	switch ( *String ) {
 474 
 475 	   /* Program name character, not allowed!	*/
 476 	   case '!'		  : 
 477 		 Error_Message( "Duplicate label names" );
 478 		 break;
 479 
 480 	   /* Label character, not allowed!		*/
 481 	   case '@'         : 
 482 		 Error_Message( "Multipul labels on a single line." );
 483 		 break;
 484 
 485 	   /* Taunt define character, not allowed! */
 486 	   case '"'		: 
 487 		 Error_Message( "Taunt not on separate line." );
 488 		 break;
 489 
 490 	   /* Taunt inbed character, not allowed! */
 491 	   case '['		: 
 492 		 Error_Message( "Taunt inbed not after instruction." );
 493 		 break;
 494 
 495 	   /* Data character, increase instruction counter    */
 496 	   case '#'         : InstrCount++;
 497 					  break;
 498 
 499 	   /* Program comment character, ignore line */
 500 	   case '/'         : break;	
 501 
 502 	   /* NULL or newline, do nothing		 */
 503 	   case NULL        : 
 504 	   case '\n'		: break;
 505 
 506 	   /* OTHERWISE, Make sure it's text, else error   */
 507 	   default		: if ( CheckMnemonic(String) != BADMNEMONIC )
 508 
 509 						/* Assume an instruction */
 510 						InstrCount++;
 511 
 512 					  else
 513 
 514 						/* Otherwise it is garbage */
 515 						Error_Message("Garbage text found.");
 516 
 517 					  /* end if */
 518 
 519 	  }; /* end case */
 520 
 521 
 522    /* DONE!! */
 523 
 524 
 525 }; /* end Find_More */
 526 
 527 
 528 
 529 /* --------------- SetLabel ---------------*/
 530 void  Set_Label( char  *String ) {
 531 
 532 	int            Step  = 0;    /* Looping var 				           */
 533 	static int	Value;        /* Hold value for number. Force to DGROUP */
 534 	struct Label   *Node,
 535 				*Last;       /* Pointer into label chain           */
 536 	char			Text[10],    /* Temp hold for label text	      */
 537 				*FindEq;     /* Walk the String in search of and = */
 538 
 539 
 540   /* If no label has yet been defined, define this one to start chain */
 541   if (FirstLabel == NULL) {
 542 
 543 	   FirstLabel = (struct Label *)malloc(sizeof(struct Label));/* Make node */
 544 	   FirstLabel->Next   = NULL;
 545 	   FirstLabel->Offset = InstrCount; /* Set this offset for the label*/
 546 
 547 	   /* Stuff label text */
 548 	   while ( (*String != '\n')&&(Step < 10)&&(*String != ' ')&&
 549 			 (*String != '	' ) ) {
 550                 /* Tab char  ^ */
 551 		 FirstLabel->Text[Step] = *String;
 552 		 Step++;
 553 		 String++;
 554 	   };
 555 
 556 	   /* Pad text with a NULL */
 557 	   FirstLabel->Text[Step] = NULL;
 558 	   Node = FirstLabel;			/* In case we need it later */
 559 
 560 	   /* Done with first label */
 561 
 562   } else {
 563 
 564 	/* Not the first label */
 565      /* Now, move label text into local and traverse label chain to
 566 	   check for duplicate labels								*/
 567 
 568 	/* Stuff label text into temp local var */
 569      Step = 0;
 570 	while ( (*String != '\n')&&(Step < 10)&&(*String != ' ')&&
 571 	        (*String != '	' ) ) {
 572                 /* Tab char  ^ */
 573 	   Text[Step] = *String;
 574 	   Step++;
 575 	   String++;
 576 	};
 577 	Text[Step] = NULL;  /* Null terminate the temp string */
 578 
 579 	/* Now start to traverse */
 580 	Node = FirstLabel;
 581 	while ( Node != NULL ) {
 582 	   /* check for duplication */
 583 	   if ( strcmp(Text, Node->Text) == 0 ) {
 584 	      Error_Message( "Duplicate label names." );
 585 		 return;		/* Dup found!, return */	
 586 	   }; /* end if */
 587 
 588 	   /* move to next node */
 589 	   Last = Node;		/* Remember last node */
 590 	   Node = Node->Next;    /* Point to next	  */
 591 
 592 	}; /* end while */
 593 
 594 	/* We have found the last node and there is no duplication, SO add label */
 595 	Node = (struct Label *)malloc(sizeof(struct Label));  /* Make node */
 596 	Node->Next   = NULL;
 597 	Node->Offset = InstrCount; /* Set this offset for the label*/
 598      
 599 	/* Link to last in chain */
 600 	Last->Next   = Node;
 601 
 602 	/* Stuff label text */
 603 	Step = 0;
 604 	while ( (Text[Step] != NULL)&&(Step < 10)) {
 605 	   Node->Text[Step] = Text[Step];
 606 	   Step++;
 607 	}; /* end while */
 608 
 609 
 610 	/* Pad text with a NULL */
 611 	Node->Text[Step] = NULL;
 612 
 613   }; /* end if */
 614 
 615   /* --  See if this is a label set line */
 616 
 617 	/* Find WS */
 618 	FindEq = String;
 619 	while ( (*FindEq != 32)&&(*FindEq != 9)&&(*FindEq != '\n')&&
 620 	        (*FindEq != '\n') ) {
 621 	  ++FindEq;
 622 	};
 623 	/* Jump WS */
 624 	while ( (*FindEq == 32)||(*FindEq == 9) ) {
 625 	  ++FindEq;
 626 	};
 627 
 628 	/* Is there a '=' sign ? */
 629 	if ( *FindEq == '=' ) {
 630 
 631 	   /* YES!!, it is a label set line! */
 632 	   /* Find next non WS */
 633 	   ++FindEq;
 634 	   while ( (*FindEq == 32)||(*FindEq == 9) ) {
 635 		++FindEq;
 636 	   };
 637 
 638 	   /* Find the value, and place it */
 639 	   Get_Value( FindEq, &Value );
 640 	   Node->Offset = Value;
 641 
 642 	} else
 643 
 644         /* NO!! Then continue normal line processing.   		  */
 645 	   /* Call Find_More to see if there is anything else on line */
 646 	   /* String must point to char following label */
 647 	   Find_More ( String );
 648 
 649 	/* end if */
 650 
 651 	/* DONE! */
 652 
 653 }; /* end Set_Label */
 654 
 655 
 656 /* ----------- X_Label ---------------------*/
 657 int	X_Label( char  *String, int	*Op ) {
 658 
 659 	struct Label	*Node;
 660 	char	  		Text[10];
 661 	int	  		Found, Step;
 662 
 663      Found = FALSE;
 664 
 665 	/* Stuff label text into temp local var */
 666      Step = 0;
 667 	while ( (*String != '\n')&&(Step < 10)&&(*String != ' ')&&
 668 	        (*String != '	' ) ) {
 669                 /* Tab char  ^ */
 670 	   Text[Step] = *String;
 671 	   Step++;
 672 	   String++;
 673 	};
 674 	Text[Step] = NULL;  /* Null terminate the temp string */
 675 
 676 	/* Traverse until found or not found */
 677 	Node = FirstLabel;
 678 	while ( (Node != NULL)&&(Found == FALSE) ) {
 679 
 680 	   /* check for duplication */
 681 	   if ( strcmp(Text, Node->Text) == 0 ) {
 682 		 /* We found it */
 683 		 Found = TRUE;
 684 
 685 		 /* Get the data, data is an offset from current position */
 686 		 *Op = Node->Offset - InstrCount;
 687 
 688 	   }; /* end if */
 689 
 690 	   /* move to next node */
 691 	   Node = Node->Next;    /* Point to next	  */
 692 
 693 	}; /* end while */
 694 
 695 	/* if not found then error */
 696 	if (Found == FALSE) {
 697 	   Error_Message("Unknown label.");
 698 	   return (FALSE);
 699 	};
 700 
 701 	/* Otherwise, return good */
 702 	return( TRUE );
 703 
 704 }; /* end X_Label */
 705 
 706 
 707 /* ----------- Get_Operand -----------------*/
 708 char *Get_Operand ( char  *String, int  *Operand, int  *OperandT ) {
 709 
 710      /* Temporaries */
 711 	int	Op, OpT;
 712 
 713 	/* Now find the next character	*/
 714 	while ( (*String == 32)||(*String == 9) ) {
 715 	  String++;
 716 	};
 717 
 718 	/* Case through what we may have found */
 719 	switch ( *String ) {
 720 
 721 	   /* Taunt inbed character, no operand here */
 722 	   case '['  :
 723 
 724 	   /* End of line, no operand here			*/
 725 	   case '\n' :
 726 	   case NULL :                               
 727 
 728 	   /* Comment, no operand here			*/
 729 	   case '/'  : OpT = NOOPERAND;
 730 				break;
 731 
 732 	   /* Label, so go find it				*/
 733 	   case '@'  : if ( X_Label( String, &Op ) == FALSE )
 734 					OpT = ERROROPERAND;     /* An error was returned */
 735 				else
 736 					OpT = MEM;
 737 
 738 
 739 				break;
 740 
 741 	   /* Registers */
 742 	   case 'A'  :
 743 	   case 'B'  :
 744 	   case 'C'  : OpT = REG;
 745 				Op  = *String;	/* Make certain they are the same */
 746 				break;
 747 
 748 	   /* Pointer */
 749 	   case '^'  : String++;			/* Point to next character 	     */
 750 				OpT  = PTR;		/* Should be pointer type          */
 751 				/* See what type of pointer it is					*/
 752 				switch( *String ) {
 753 
 754 				   /* Register pointer	*/
 755 				   case 'A'  :
 756 				   case 'B'  :
 757 				   case 'C'  : OpT = REG;   /* Still a register */
 758 							Op  = (*String + REGPTRBIT);
 759 							break;
 760 
 761 	   			   /* Memory offset pointer  */
 762 	   			   case '+'  :
 763 				   case '-'  : if( Get_Value( String, &Op ) == FALSE ) {
 764 					             OpT = ERROROPERAND;
 765 					             Error_Message( " Invalid Offset value.");
 766 				               }; /* end if */
 767  				               break;
 768 
 769 				   /* Immediate pointer */
 770 				   case '$'  : String++;
 771                                    /* See if Error is returned */
 772 				               if( Get_Value( String, &Op ) == FALSE ) {
 773 					             OpT = ERROROPERAND;
 774 					             Error_Message( " Invalid Immediate value.");
 775 				               }; /* end if */
 776 				               break;
 777 
 778 	                 /* Label, so go find it				*/
 779 	                 case '@'  : if ( X_Label( String, &Op ) == FALSE )
 780 					            OpT = ERROROPERAND;     
 781 						    break;
 782 
 783 
 784 
 785 				   /* NOT A VALID POINTER, ERROR */
 786 				   default   : OpT = ERROROPERAND;
 787 							Error_Message(
 788 							"Pointer operand not valid type." );
 789 
 790 				}; /* end case */
 791 				break;
 792 
 793 	   /* Memory offset */
 794 	   case '+'  :
 795 	   case '-'  :	OpT	= MEM;
 796 
 797 				if( Get_Value( String, &Op ) == FALSE ) {
 798 					OpT = ERROROPERAND;
 799 					Error_Message( " Invalid Offset value.");
 800 				}; /* end if */
 801 				break;
 802 
 803 	   /* Get immediate */
 804 	   case '$'  : String++;
 805 				OpT = IMMEDIATE;
 806 
 807                     /* See if Error is returned */
 808 				if( Get_Value( String, &Op ) == FALSE ) {
 809 					OpT = ERROROPERAND;
 810 					Error_Message( " Invalid Immediate value.");
 811 				}; /* end if */
 812 				break;
 813 
 814 	   /* Anything else is an error */
 815 	   default   : OpT  = ERROROPERAND;
 816 				Error_Message( "Unknown operand type." );
 817 
 818 	}; /* end case */
 819 
 820 	/* Report the values */
 821 	*Operand  = Op;
 822      *OperandT = OpT;
 823 
 824 	/* Make sure String is returned pointing at whitespace, if no taunt */
 825 	if ( *String != '[' )
 826 
 827 	   while ((*String != ' ')&&(*String != 9)&&(*String != NULL)&&
 828 		     (*String != '\n')) {
 829 	      String++;
 830 	   };
 831 
 832 	/* end if */
 833 
 834 	return( String );
 835 
 836 }; /* end Get_Operand */
 837 
 838 
 839 /* ----------- Data_Instr ------------------*/
 840 void Data_Instr ( char  *String ) {
 841 
 842 	char			InstrBBuf[5];  /* Buffer for binary data		 */
 843 
 844 	long	int		Number;		/* Number obtained by the translate */
 845 
 846 	unsigned int	TempInt = 0;
 847 
 848      struct Instr   Instruction;
 849 
 850 
 851 	/* Adjust back the instr counter for list file */
 852 	InstrPut++;
 853 
 854 	/* Look at next char 	    */
 855 	String++;
 856 
 857 	/* Get value and look for error */
 858 	if ( Get_Value( String, &Number ) == FALSE ) {
 859 
 860         /* Error occured */
 861 	   InstrCount++;
 862         return;
 863 
 864 	}; /* end if */
 865 
 866 	/* Generate instruction */
 867 	Instruction.Token    = DAT;
 868 	Instruction.OpToken  = 0;
 869 	Instruction.Operand1 = Number;	/* Stuff data into first  operand	*/
 870 	Instruction.Operand2 = 0;
 871 	Instruction.BOS	 = 0;
 872 
 873 	/* Put the instruction to the file */
 874 	fwrite( &Instruction, sizeof(struct Instr), 1, OutFile );
 875 
 876      /* if list file is enabled, then put the instruction binary data int
 877 	 the list file buffer									 */
 878      if ( ListFile == TRUE ) {
 879 	 
 880 	  TempInt = Instruction.Token;
 881 	  TempInt = TempInt << 8;	     		  /* Move to high byte */
 882 	  TempInt = TempInt + Instruction.OpToken; /* Add TokenOp byte  */
 883 	  sprintf( InstrBinary, "%04x", TempInt );
 884 
 885 	  strcat( InstrBinary, ":" );
 886 
 887 	  TempInt = Instruction.Operand1;
 888 	  sprintf( InstrBBuf, "%04x", TempInt );
 889 	  strcat( InstrBinary, InstrBBuf );
 890 
 891 	  strcat( InstrBinary, ":" );
 892 
 893 	  TempInt = Instruction.Operand2;
 894 	  sprintf( InstrBBuf, "%04x", TempInt );
 895 
 896        strcat( InstrBinary, InstrBBuf );
 897 
 898      }; /* end if */
 899 
 900 	/* Find white space or eoln */
 901 	while ( (*String != ' ')&&(*String != '\t')&&(*String != '\n') ) {
 902 	   String++;
 903 	};
 904 
 905 	/* Now insure the line ends or there is a comment	*/
 906 	while ( (*String == ' ')||(*String == '\t') ) {
 907 	  String++;
 908 	};
 909 
 910 	/* case through possibilities */
 911 	switch( *String ) {
 912 
 913 		/* Comment character, OK!, move on   */
 914 		case  '/'	    : break;
 915 
 916 		/* Taunt imbed, not allowed for data */
 917 		case  '['	    : Error_Message("Taunt imbed not allowed on data.");
 918 					 break;
 919 
 920 		/* End of line, OK!, move on		  */
 921 		case  NULL    :
 922 		case  '\n'    : break;
 923 
 924 		/* Otherwise there is an error	  */
 925 		default	    : Error_Message("Incorrect Syntax.");
 926 
 927 	}; /* end case */
 928 
 929 	/* Up instruction counter */
 930 	InstrCount++;
 931 
 932 	/* DONE! */
 933 
 934 }; /* end Data_Instr */
 935 
 936 
 937 /* ----------- Imbed_Taunt -----------------*/
 938 int  Imbed_Taunt ( unsigned char  *Token, char   *String ) {
 939 
 940    unsigned char  TauntNum;
 941 
 942 
 943    /* First see if is a DAT instruction.  TAUNTS not allowed */
 944    if ( *Token == DAT ) {
 945 	 Error_Message("Taunt imbed not allowed on data");
 946 	 return(FALSE);
 947    }; /* end if */
 948 
 949   /* Point to taunt number */
 950    String++;
 951 
 952    /* See is taunt number is in range */
 953    if ( ( *String < '0' ) || ( *String > '7' ) ) {
 954 
 955 	 /* Taunt number out of range.  !!ERROR!! */
 956 	 Error_Message("Taunt number out of range.");
 957 	 return( FALSE );
 958 
 959    }; /* end if */
 960 
 961    /* Get taunt number */
 962    TauntNum = *String - '0';
 963 
 964    /* If taunt not defined then ERROR */
 965    if ( TauntUsage[TauntNum] == FALSE ) {
 966 	 Error_Message("Taunt not defined.");
 967 	 return(FALSE);
 968    }; /* end if */    
 969 
 970     /* Shift the number into 64/32/16 bits */
 971    TauntNum = TauntNum << 4;
 972 
 973    /* Flag that a taunt is present */
 974    TauntNum = TauntNum + TauntPresent;
 975 
 976    /* Combine with token */
 977    *Token = *Token + TauntNum;
 978 
 979    /* DONE, return good */
 980    return( TRUE );
 981 
 982 }; /* end Imbed_Taunt */
 983 
 984 
 985 /* ----------- Code_Instr ------------------*/
 986 void Code_Instr ( char  *String ) {
 987 
 988    char	Mnemonic[4],
 989 		InstrBBuf[5];
 990 
 991    int	Step;
 992 
 993    unsigned char	Token,
 994 				OpsAll;
 995    unsigned char	OperandToken;
 996 
 997    struct Instr     Instruction;
 998 
 999    unsigned int	TempInt;
1000 
1001 
1002 
1003    /* Adjust back the insrt counter for list file */
1004    InstrPut++;
1005 
1006    /* Get the mnemonic position in table */
1007    Step = CheckMnemonic( String );
1008 
1009    /* if Step indicates a bad mnemonic, then return */
1010    if ( Step == BADMNEMONIC ) return;
1011 
1012    /* Extract the token */
1013    Token  = TokenTable[Step].Token;
1014    OpsAll = TokenTable[Step].OpsAllowed;
1015 
1016    /* Now point to whitespace	*/
1017    while ( (*String != 32)&&(*String != 9)&&(*String != '\n') ) {
1018 	  String++;
1019    };
1020 
1021    /* -- Pop operands -- */
1022 
1023    Operand2		 = 0;
1024    OperandToken      = 0;
1025    OperandType2      = 0;
1026 
1027    /* Get the operands */
1028    String = Get_Operand( String, &Operand1, &OperandType1);  
1029    if ( OperandType1 != NOOPERAND )
1030 	   String = Get_Operand( String, &Operand2, &OperandType2 );
1031 
1032    /* If either operands have an error then return */
1033    if ( (Operand1 == ERROROPERAND) || (Operand2 == ERROROPERAND) ) return;
1034 
1035    /* Built Operand Token */
1036    OperandType1 	= OperandType1 << 4;	      /* Shift into MSBs     */
1037    OperandToken     = OperandType1 + OperandType2; /* Mrg into token byte */
1038 
1039    /* Let's see if there is an illegal operand */
1040    if ( OperandToken != (OperandToken & OpsAll) ) {
1041 
1042 	 /* The OperandToken does not fit in the Allowed Operands !!ERROR!! */
1043 
1044 	 /* Peel off the LSBs token and see if problem is there */
1045 	 OperandToken = OperandToken & 0x0F;
1046 	 OpsAll	    = OpsAll & 0x0F;		/* Eliminates the MSBs */
1047 
1048 	 if ( OperandToken != OperandToken & OpsAll )
1049 		/* Error in the LSBs token */
1050 
1051 		/* See if it is because there is no second operand */
1052 		if ( OpsAll == 0 )
1053 			Error_Message("Instruction does not have second operand.");
1054 		else
1055 			Error_Message("Second operand not an allowed type.");
1056 
1057 	 else {
1058 		/* Error in MSBs token */
1059 		Error_Message("First operand not an allowed type.");
1060 
1061 	     /* Up instruction counter */
1062 		InstrCount++;
1063 
1064 		return;
1065 
1066       }; /* end if */
1067 
1068    }; /* end error ops if */
1069 
1070 
1071    /* ------ We should have a valid instruction ------ */
1072 
1073    /* -- See if we have a taunt imbed on this line --- */
1074    /* Now find the next character	*/
1075    while ( (*String == 32)||(*String == 9) ) {
1076 	 String++;
1077    };
1078 
1079    /* If it is the imbed char then do the imbed */
1080    if ( *String == '[' )
1081 	 if ( Imbed_Taunt( &Token, String ) == FALSE ) {
1082 	    /* Error occured in imbed, return */
1083 
1084 	    /* Up instruction counter */
1085 	    InstrCount++;
1086 
1087          return;
1088 
1089       }; /* end if */
1090 
1091    /* Build the instruction */
1092    Instruction.Token 	= Token;
1093    Instruction.OpToken   = OperandToken;
1094    Instruction.Operand1  = Operand1;
1095    Instruction.Operand2  = Operand2;
1096    Instruction.BOS		= NULL;
1097 
1098    /* Put the instruction to the file */
1099    fwrite( &Instruction, sizeof(struct Instr), 1, OutFile );
1100 
1101    /* if list file is enabled, then put the instruction binary data int
1102 	 the list file buffer									 */
1103    if ( ListFile == TRUE ) {
1104 	 
1105 	 TempInt = Instruction.Token;
1106 	 TempInt = TempInt << 8;	     		  /* Move to high byte */
1107 	 TempInt = TempInt + Instruction.OpToken; /* Add TokenOp byte  */
1108 	 sprintf( InstrBinary, "%04x", TempInt );
1109 
1110 	 strcat( InstrBinary, ":" );
1111 
1112 	 TempInt = Instruction.Operand1;
1113 	 sprintf( InstrBBuf, "%04x", TempInt );
1114 	 strcat( InstrBinary, InstrBBuf );
1115 
1116 	 strcat( InstrBinary, ":" );
1117 
1118 	 TempInt = Instruction.Operand2;
1119 	 sprintf( InstrBBuf, "%04x", TempInt );
1120 
1121       strcat( InstrBinary, InstrBBuf );
1122 
1123    }; /* end if */
1124 
1125    /* Up instruction counter */
1126    InstrCount++;
1127 
1128 }; /* end Code_Instr */
1129 
1130 
1131 /* ----------- Lable_Line ------------------*/
1132 void Label_Line ( char  *String ) {
1133 
1134 
1135 	/* Find first white space */
1136 	while ( (*String != 32)&&(*String != 9)&&(*String != NULL)&&
1137 		   (*String != '\n' ) ) {
1138 	   String++;
1139 	};
1140 
1141      /* See is anything else on line		*/
1142 	while ( (*String == 32)||(*String == 9) ) {
1143 		String++;
1144 	};
1145 
1146 	/* case through possibilities */
1147 	switch ( *String ) {
1148 
1149 
1150 	   /* Data character, DATA!, put it into an instruction   */
1151 	   case '#'         : Data_Instr( String );
1152 					  break;
1153 
1154 	   /* If it was a label set line, do nothing  		   */
1155 	   case '='		:
1156 
1157 	   /* NULL or newline, do nothing, it's an empty line	   */
1158 	   case NULL        :
1159 	   case '\n'		: break;
1160 
1161 	   /* OTHERWISE, assume it is an instruction and parse it */
1162 	   default		: Code_Instr( String );
1163 
1164 	  }; /* end case */
1165 
1166 
1167    /* DONE!! */
1168 
1169 
1170 }; /* end Label_Line */
1171 
1172 /* --------------- ListHeader --------------- */
1173 void  ListHeader() {
1174 
1175    /* Put header lines */
1176    fputs("\n\r !! Battle Operating System !!  (C) 1993 Erich P Gatejen\n\r",
1177          ListF );
1178    fputs(" Battle Operating system Assembler ( BOA ) -\n\r\n\r", ListF );
1179    fputs("Assembly list for program file :", ListF );
1180    fputs( FileOut, ListF );
1181    fputs("\n\r\n\r", ListF );
1182 
1183 }; /* end ListHeader */
1184 
1185 
1186 /* --- Primary routines --------------------------------------------*/
1187 
1188 /* -- PassOne  : Do the first pass of the assembly -- */
1189 void	 PassOne () {
1190 
1191 	char		LineBuffer[81];
1192 	int 		Step;
1193 
1194 
1195    LineBuffer[81] = 0;
1196 
1197    /* Reset the instruction counter */
1198    InstrCount     = 0;
1199 
1200    /* Process file line at a time until end of file */
1201 	while ( !feof( InFile ) ) {
1202 
1203 	   /* Get the line */
1204 	   fgets( LineBuffer, 80, InFile );
1205 
1206 	   /* If a list file is enabled, then put it in */
1207 	   if ( ListFile == TRUE ) {
1208 
1209 		 fprintf( ListF, "%4u ", LineCount );
1210            fputs( LineBuffer, ListF );
1211 
1212 	   }; /* end if */
1213 
1214 	   /* Find the first character of the line ( or no character ) */
1215 	   Step = 0;
1216 	   while ( (LineBuffer[Step] == 32)||(LineBuffer[Step] == 9) ) {
1217 		 Step++;
1218 	   };
1219 
1220 	   /* Case through the posible lines */
1221 	   switch( LineBuffer[Step] ) {
1222 
1223 		/* Program name character	*/
1224 		case '!'		  : Get_Prog_Name( &LineBuffer[Step]);
1225 					    break;
1226 
1227 		/* Label character			*/
1228 		case '@'         : Set_Label( &LineBuffer[Step]);
1229 					    break;
1230 
1231 		/* Taunt define character */
1232 		case '"'		  : Set_Taunt( &LineBuffer[Step]);
1233 					    break;
1234 
1235 		/* Data character, increase instruction counter    */
1236 		case '#'         : InstrCount++;
1237 					    break;
1238 
1239 		/* Program comment character, ignore line */
1240 		case '/'         : break;	
1241 
1242 	     /* Taunt inbed character, not allowed! */
1243 	     case '['		  : 
1244 		 Error_Message( "Taunt inbed not after instruction." );
1245 		 break;
1246 
1247 		/* NULL or newline, do nothing		 */
1248 		case NULL        : 
1249 		case '\n'        : break;
1250 
1251 		/* OTHERWISE, Check Mnemonic, else error   */
1252 		default		  : if ( CheckMnemonic( &(LineBuffer[Step]) ) !=
1253 						    BADMNEMONIC )
1254 
1255 						  /* Assume an instruction */
1256 						  InstrCount++;
1257 
1258 	  }; /* end case */
1259 
1260 	LineCount++;	/* Point to the next line */
1261 
1262 	}; /* end while */
1263 
1264 }; /* end PassOne */
1265 
1266 
1267 /* -- DoBOSHeader : Write the BOS executable file header to the output file */
1268 void  DoBOSHeader () {
1269 
1270    /* Write BOS version discriptor and copyright */
1271    fputc( VERSIONDISC,     OutFile );
1272    fputs( COPYRIGHTNOTICE, OutFile );
1273 
1274    /* Adjust instruction count for next write */
1275    InstrCount++;  /* Adjust count.  From 1 instead of 0 */
1276 
1277    /* Write word containing program size */
1278    fwrite( &InstrCount, sizeof( unsigned int), 1,  OutFile );
1279 
1280    /* Write the program name and taunt list */
1281    fwrite( ProgName, sizeof( char ), PROGNAMESIZE, OutFile );
1282    fwrite( Taunts,   TAUNTSIZE,      TAUNTSNUMBER, OutFile );
1283 
1284    
1285 }; /* end DoBOSHeader */
1286 
1287 
1288 /* -- PassTwo  : Do the second pass of the assembly -- */
1289 void	 PassTwo () {
1290 
1291 	char		LineBuffer[81];
1292      char      ListBuffer[60];
1293 	int 		Step, TabStep, PutStep;
1294 	
1295 
1296 	LineBuffer[81] = 0;
1297 	LineCount      = 1;	/* Reset the line counter */
1298 
1299 	PassTwoF       = TRUE; /* Flag pass two is underway */
1300 
1301    /* Reset the instruction counter */
1302    InstrCount     = 0;
1303 
1304    /* Process file line at a time until end of file */
1305    while ( !feof( InFile ) ) {
1306 
1307 	   /* If list file is enabled then take the time to clear the first
1308 		 40 chars of the LineBuffer							*/
1309         if ( ListFile == TRUE )
1310 		 for ( Step = 0; Step < 55; Step++ ) LineBuffer[Step] = NULL;
1311 
1312 	   /* Get the line */
1313 	   fgets( LineBuffer, 80, InFile );
1314 
1315 
1316 	   /* If a list file is enabled, Put line to file */
1317 	   if ( ListFile == TRUE ) {
1318 
1319            /* Kill the binary data */
1320            InstrBinary[0] = NULL;
1321 
1322 		 PutStep = 0;
1323 		 Step    = 0;
1324 
1325 		 while ( PutStep < 55 ) {
1326 		    
1327 		    /* if Null or LF then put a space */
1328 		    if ( (LineBuffer[Step] == '\n')||(LineBuffer[Step] == NULL ) )
1329 
1330 			  /* Turn LFs and Nulls into spaces */
1331 			  ListBuffer[PutStep] = ' ';
1332 
1333 		    else
1334 
1335 			  /* Otherwise, check for tab */
1336 			  if ( LineBuffer[Step] != '\t' )
1337 
1338                     /* Not TAB, straight copy */
1339 				ListBuffer[PutStep] = LineBuffer[Step];
1340 
1341 			  else {
1342 
1343                     /* Convert the TAB to five spaces */
1344 				for ( TabStep = 0; TabStep < 5; TabStep++ ) {
1345 				 
1346 				   /* Put space */
1347 			        ListBuffer[PutStep] = ' ';
1348 
1349 				   /* Increment the Step counter */
1350                        PutStep++;
1351 
1352 				}; /* end for */ 
1353 
1354 				/* Adjust PutStep down */
1355 				PutStep--;
1356 
1357 			  }; /* end if */
1358 
1359 		    /* end if */
1360 
1361 		    Step++;
1362               PutStep++;
1363 
1364 		 }; /* end while */
1365 
1366 		 /* Make sure the line is always only 53 chars */
1367 		 ListBuffer[55] = NULL;
1368     
1369 		 /* Do adjust to instr. count for a list file */
1370 		 InstrPut = InstrCount-1;
1371 					 
1372         }; /* end if */
1373 
1374 	   /* Find the first character of the line ( or no character ) */
1375 	   Step = 0;
1376 	   while ( (LineBuffer[Step] == 32)||(LineBuffer[Step] == 9)) {
1377 		 Step++;
1378         };
1379 
1380 	   /* Case through the posible lines */
1381 	   switch( LineBuffer[Step] ) {
1382 
1383 		/* Label character, look for instruction on this line	*/
1384 		case '@'         : Label_Line( &LineBuffer[Step]);
1385 					    break;
1386 
1387 		/* Data character, DATA! put it into an instruction	*/
1388 		case '#'         : Data_Instr( &LineBuffer[Step]);
1389 					    break;
1390 
1391 		/* Taunt define character, ignore this line  		*/
1392 		case '"'		  : break;
1393 
1394 		/* Program name character, ignore this line	*/
1395 		case '!'		  : 	
1396 
1397 		/* Program comment character, ignore line */
1398 		case '/'         : 
1399 
1400 		/* Taunt inbed character, not allowed!, should have been caught
1401 		   on the first pass									 */
1402 
1403 
1404 		/* NULL or newline, do nothing		 */
1405 		case NULL        : 
1406 		case '\n'        : break;
1407 
1408 		/* OTHERWISE, assume it is an instruction and parse it  */
1409 		default		  : Code_Instr( &LineBuffer[Step] );
1410 
1411 	 }; /* end case */
1412 
1413       /* Is there a list file */
1414 	 if ( ListFile == TRUE ) {
1415 
1416 	    /* Adjust if went negetive */
1417 	    if ( InstrPut > 65355 ) InstrPut = 0;
1418 
1419 	    /* Put standard data */
1420 	    fprintf( ListF, "%04u :", InstrPut );
1421 	    fputs(   ListBuffer, ListF );
1422 
1423 	    /* If the binary string has data, then write it too */
1424 	    if ( InstrBinary[0] != NULL ) {
1425 
1426 		  fputs( InstrBinary, ListF );
1427 
1428 	    }; /* end if */
1429 
1430 	    /* Now write the return */
1431 	    fputc( '\n', ListF );
1432 
1433 	 }; /* end if */
1434 
1435 	 LineCount++;	/* Point to the next line */
1436 
1437    }; /* end while */
1438 
1439 }; /* end PassTwo */
1440 
1441 
1442 /* --- MAIN --------------------------------------------------------*/
1443 
1444 void main ( int argc, char *argv[] ) {
1445 
1446 	char		*FileName;	/* Pointer to filename from command line */
1447 
1448  /* Message the opening									 */
1449 	Do_Opening();
1450 
1451 
1452  /* Get file name from command line and pass it to file open func */
1453 	/* Check to see if there is a file name, if not message and exit */
1454 	if (argc < 2 ) {
1455 		Message_No_File();
1456 		Message_Bye();
1457 		exit(0);
1458 	};
1459 
1460 	/* Do open file, if non-zero returned then message user and end */
1461 	if (OpenFiles( argv[1] )) {
1462 		Message_Bye();
1463 		exit(0);
1464 	};
1465 
1466 	/* See if the user wants a list file, if so then set it up */
1467 	if (argc > 2) 
1468 
1469 		/* If the list file name was valid, then open and flag */
1470 		if (OpenList( argv[2] ) == TRUE) {
1471 
1472              /* Enable list file outputs */
1473 		   ListFile = TRUE;
1474 		   
1475 		   /* Put the header to the file */ 
1476 		   ListHeader();
1477 
1478 		}; /* end if */
1479 	
1480 
1481  /* Do pass one, quit if errors found                    	   */
1482 	PassOne();
1483 	if (ErrorCount) {
1484 		CloseFilesK();
1485 		Message_ASM_Abort();
1486 		exit(0);
1487 	};
1488 
1489 	/* Survived pass one, if list file is enabled then kill it and
1490 	   start second pass listing							*/
1491 	if ( ListFile == TRUE ) {
1492 
1493 	   rewind( ListF );
1494 	   ListHeader();
1495 
1496 	};
1497 
1498 	/* Reset the input file and write .BOS header	   		*/
1499 	rewind( InFile );
1500 	DoBOSHeader();
1501 
1502 	/* Do pass two, quit if errors found                        */
1503 	PassTwo();
1504 	if (ErrorCount) {
1505 		CloseFilesK();
1506 		Message_ASM_Abort();
1507 		exit(0);
1508 	};
1509 		
1510 
1511 	/* Done.  Clean up.  Close files. 						   */
1512 	CloseFiles();
1513 	Message_Bye();
1514 
1515 
1516 }; /* end main */