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