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