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 */
|