]> git.sur5r.net Git - cc65/blob - src/ca65/main.c
Added a new option --macpack-dir that allows to load the macro packages
[cc65] / src / ca65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                 Main program for the ca65 macroassembler                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2005, Ullrich von Bassewitz                                      */
10 /*                Römerstraße 52                                             */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40
41 /* common */
42 #include "addrsize.h"
43 #include "chartype.h"
44 #include "cmdline.h"
45 #include "mmodel.h"
46 #include "print.h"
47 #include "target.h"
48 #include "tgttrans.h"
49 #include "version.h"
50
51 /* ca65 */
52 #include "abend.h"
53 #include "asserts.h"
54 #include "error.h"
55 #include "expr.h"
56 #include "feature.h"
57 #include "filetab.h"
58 #include "global.h"
59 #include "incpath.h"
60 #include "instr.h"
61 #include "istack.h"
62 #include "lineinfo.h"
63 #include "listing.h"
64 #include "macpack.h"
65 #include "macro.h"
66 #include "nexttok.h"
67 #include "objfile.h"
68 #include "options.h"
69 #include "pseudo.h"
70 #include "scanner.h"
71 #include "segment.h"
72 #include "sizeof.h"
73 #include "spool.h"
74 #include "symtab.h"
75 #include "ulabel.h"
76
77
78
79 /*****************************************************************************/
80 /*                                   Code                                    */
81 /*****************************************************************************/
82
83
84
85 static void Usage (void)
86 /* Print usage information and exit */
87 {
88     printf ("Usage: %s [options] file\n"
89             "Short options:\n"
90             "  -D name[=value]\tDefine a symbol\n"
91             "  -I dir\t\tSet an include directory search path\n"
92             "  -U\t\t\tMark unresolved symbols as import\n"
93             "  -V\t\t\tPrint the assembler version\n"
94             "  -W n\t\t\tSet warning level n\n"
95             "  -g\t\t\tAdd debug info to object file\n"
96             "  -h\t\t\tHelp (this text)\n"
97             "  -i\t\t\tIgnore case of symbols\n"
98             "  -l\t\t\tCreate a listing if assembly was ok\n"
99             "  -mm model\t\tSet the memory model\n"
100             "  -o name\t\tName the output file\n"
101             "  -s\t\t\tEnable smart mode\n"
102             "  -t sys\t\tSet the target system\n"
103             "  -v\t\t\tIncrease verbosity\n"
104             "\n"
105             "Long options:\n"
106             "  --auto-import\t\tMark unresolved symbols as import\n"
107             "  --cpu type\t\tSet cpu type\n"
108             "  --debug-info\t\tAdd debug info to object file\n"
109             "  --feature name\tSet an emulation feature\n"
110             "  --help\t\tHelp (this text)\n"
111             "  --ignore-case\t\tIgnore case of symbols\n"
112             "  --include-dir dir\tSet an include directory search path\n"
113             "  --listing\t\tCreate a listing if assembly was ok\n"
114             "  --list-bytes n\tMaximum number of bytes per listing line\n"
115             "  --macpack-dir dir\tSet a macro package directory\n"
116             "  --memory-model model\tSet the memory model\n"
117             "  --pagelength n\tSet the page length for the listing\n"
118             "  --smart\t\tEnable smart mode\n"
119             "  --target sys\t\tSet the target system\n"
120             "  --verbose\t\tIncrease verbosity\n"
121             "  --version\t\tPrint the assembler version\n",
122             ProgName);
123 }
124
125
126
127 static void SetOptions (void)
128 /* Set the option for the translator */
129 {
130     char Buf [256];
131
132     /* Set the translator */
133     sprintf (Buf, "ca65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
134     OptTranslator (Buf);
135
136     /* Set date and time */
137     OptDateTime ((unsigned long) time(0));
138 }
139
140
141
142 static void NewSymbol (const char* SymName, long Val)
143 /* Define a symbol with a fixed numeric value in the current scope */
144 {
145     ExprNode* Expr;
146
147     /* Search for the symbol, allocate a new one if it doesn't exist */
148     SymEntry* Sym = SymFind (CurrentScope, SymName, SYM_ALLOC_NEW);
149
150     /* Check if have already a symbol with this name */
151     if (SymIsDef (Sym)) {
152         AbEnd ("`%s' is already defined", SymName);
153     }
154
155     /* Generate an expression for the symbol */
156     Expr = GenLiteralExpr (Val);
157
158     /* Mark the symbol as defined */
159     SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_NONE);
160 }
161
162
163
164 static void CBMSystem (const char* Sys)
165 /* Define a CBM system */
166 {
167     NewSymbol ("__CBM__", 1);
168     NewSymbol (Sys, 1);
169 }
170
171
172
173 static void SetSys (const char* Sys)
174 /* Define a target system */
175 {
176     switch (Target = FindTarget (Sys)) {
177
178         case TGT_NONE:
179             break;
180
181         case TGT_MODULE:
182             AbEnd ("Cannot use `module' as a target for the assembler");
183             break;
184
185         case TGT_ATARI:
186             NewSymbol ("__ATARI__", 1);
187             break;
188
189         case TGT_C16:
190             CBMSystem ("__C16__");
191             break;
192
193         case TGT_C64:
194             CBMSystem ("__C64__");
195             break;
196
197         case TGT_VIC20:
198             CBMSystem ("__VIC20__");
199             break;
200
201         case TGT_C128:
202             CBMSystem ("__C128__");
203             break;
204
205         case TGT_ACE:
206             CBMSystem ("__ACE__");
207             break;
208
209         case TGT_PLUS4:
210             CBMSystem ("__PLUS4__");
211             break;
212
213         case TGT_CBM510:
214             CBMSystem ("__CBM510__");
215             break;
216
217         case TGT_CBM610:
218             CBMSystem ("__CBM610__");
219             break;
220
221         case TGT_PET:
222             CBMSystem ("__PET__");
223             break;
224
225         case TGT_BBC:
226             NewSymbol ("__BBC__", 1);
227             break;
228
229         case TGT_APPLE2:
230             NewSymbol ("__APPLE2__", 1);
231             break;
232
233         case TGT_APPLE2ENH:
234             NewSymbol ("__APPLE2ENH__", 1);
235             break;
236
237         case TGT_GEOS:
238             /* Do not handle as a CBM system */
239             NewSymbol ("__GEOS__", 1);
240             break;
241
242         case TGT_LUNIX:
243             NewSymbol ("__LUNIX__", 1);
244             break;
245
246         case TGT_ATMOS:
247             NewSymbol ("__ATMOS__", 1);
248             break;
249
250         case TGT_NES:
251             NewSymbol ("__NES__", 1);
252             break;
253
254         case TGT_SUPERVISION:
255             NewSymbol ("__SUPERVISION__", 1);
256             break;
257
258         case TGT_LYNX:
259             NewSymbol ("__LYNX__", 1);
260             break;
261
262         default:
263             AbEnd ("Invalid target name: `%s'", Sys);
264
265     }
266
267     /* Initialize the translation tables for the target system */
268     TgtTranslateInit ();
269 }
270
271
272
273 static void DefineSymbol (const char* Def)
274 /* Define a symbol from the command line */
275 {
276     const char* P;
277     unsigned I;
278     long Val;
279     char SymName [MAX_STR_LEN+1];
280
281
282     /* The symbol must start with a character or underline */
283     if (Def [0] != '_' && !IsAlpha (Def [0])) {
284         InvDef (Def);
285     }
286     P = Def;
287
288     /* Copy the symbol, checking the rest */
289     I = 0;
290     while (IsAlNum (*P) || *P == '_') {
291         if (I <= MAX_STR_LEN) {
292             SymName [I++] = *P;
293         }
294         ++P;
295     }
296     SymName [I] = '\0';
297
298     /* Do we have a value given? */
299     if (*P != '=') {
300         if (*P != '\0') {
301             InvDef (Def);
302         }
303         Val = 0;
304     } else {
305         /* We have a value */
306         ++P;
307         if (*P == '$') {
308             ++P;
309             if (sscanf (P, "%lx", &Val) != 1) {
310                 InvDef (Def);
311             }
312         } else {
313             if (sscanf (P, "%li", &Val) != 1) {
314                 InvDef (Def);
315             }
316         }
317     }
318
319     /* Define the new symbol */
320     NewSymbol (SymName, Val);
321 }
322
323
324
325 static void OptAutoImport (const char* Opt attribute ((unused)),
326                            const char* Arg attribute ((unused)))
327 /* Mark unresolved symbols as imported */
328 {
329     AutoImport = 1;
330 }
331
332
333
334 static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
335 /* Handle the --cpu option */
336 {
337     cpu_t CPU = FindCPU (Arg);
338     if (CPU == CPU_UNKNOWN) {
339         AbEnd ("Invalid CPU: `%s'", Arg);
340     } else {
341         SetCPU (CPU);
342     }
343 }
344
345
346
347 static void OptDebugInfo (const char* Opt attribute ((unused)),
348                           const char* Arg attribute ((unused)))
349 /* Add debug info to the object file */
350 {
351     DbgSyms = 1;
352 }
353
354
355
356 static void OptFeature (const char* Opt attribute ((unused)), const char* Arg)
357 /* Set an emulation feature */
358 {
359     /* Set the feature, check for errors */
360     if (SetFeature (Arg) == FEAT_UNKNOWN) {
361         AbEnd ("Illegal emulation feature: `%s'", Arg);
362     }
363 }
364
365
366
367 static void OptHelp (const char* Opt attribute ((unused)),
368                      const char* Arg attribute ((unused)))
369 /* Print usage information and exit */
370 {
371     Usage ();
372     exit (EXIT_SUCCESS);
373 }
374
375
376
377 static void OptIgnoreCase (const char* Opt attribute ((unused)),
378                            const char* Arg attribute ((unused)))
379 /* Ignore case on symbols */
380 {
381     IgnoreCase = 1;
382 }
383
384
385
386 static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
387 /* Add an include search path */
388 {
389     AddIncludePath (Arg);
390 }
391
392
393
394 static void OptListBytes (const char* Opt, const char* Arg)
395 /* Set the maximum number of bytes per listing line */
396 {
397     unsigned Num;
398     char     Check;
399
400     /* Convert the argument to a number */
401     if (sscanf (Arg, "%u%c", &Num, &Check) != 1) {
402         AbEnd ("Invalid argument for option `%s'", Opt);
403     }
404
405     /* Check the bounds */
406     if (Num != 0 && (Num < MIN_LIST_BYTES || Num > MAX_LIST_BYTES)) {
407         AbEnd ("Argument for option `%s' is out of range", Opt);
408     }
409
410     /* Use the value */
411     SetListBytes (Num);
412 }
413
414
415
416 static void OptListing (const char* Opt attribute ((unused)),
417                         const char* Arg attribute ((unused)))
418 /* Create a listing file */
419 {
420     Listing = 1;
421 }
422
423
424
425 static void OptMacPackDir (const char* Opt attribute ((unused)), const char* Arg)
426 /* Set a macro package directory */
427 {
428     /* Use the directory */
429     MacPackSetDir (Arg);
430 }
431
432
433
434 static void OptMemoryModel (const char* Opt, const char* Arg)
435 /* Set the memory model */
436 {
437     mmodel_t M;
438
439     /* Check the current memory model */
440     if (MemoryModel != MMODEL_UNKNOWN) {
441         AbEnd ("Cannot use option `%s' twice", Opt);
442     }
443
444     /* Translate the memory model name and check it */
445     M = FindMemoryModel (Arg);
446     if (M == MMODEL_UNKNOWN) {
447         AbEnd ("Unknown memory model: %s", Arg);
448     } else if (M == MMODEL_HUGE) {
449         AbEnd ("Unsupported memory model: %s", Arg);
450     }
451
452     /* Set the memory model */
453     SetMemoryModel (M);
454 }
455
456
457
458 static void OptPageLength (const char* Opt attribute ((unused)), const char* Arg)
459 /* Handle the --pagelength option */
460 {
461     int Len = atoi (Arg);
462     if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
463         AbEnd ("Invalid page length: %d", Len);
464     }
465     PageLength = Len;
466 }
467
468
469
470 static void OptSmart (const char* Opt attribute ((unused)),
471                       const char* Arg attribute ((unused)))
472 /* Handle the -s/--smart options */
473 {
474     SmartMode = 1;
475 }
476
477
478
479 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
480 /* Set the target system */
481 {
482     SetSys (Arg);
483 }
484
485
486
487 static void OptVerbose (const char* Opt attribute ((unused)),
488                         const char* Arg attribute ((unused)))
489 /* Increase verbosity */
490 {
491     ++Verbosity;
492 }
493
494
495
496 static void OptVersion (const char* Opt attribute ((unused)),
497                         const char* Arg attribute ((unused)))
498 /* Print the assembler version */
499 {
500     fprintf (stderr,
501              "ca65 V%u.%u.%u - %s\n",
502              VER_MAJOR, VER_MINOR, VER_PATCH, Copyright);
503 }
504
505
506
507 static void DoPCAssign (void)
508 /* Start absolute code */
509 {
510     long PC = ConstExpression ();
511     if (PC < 0 || PC > 0xFFFFFF) {
512         Error ("Range error");
513     } else {
514         SetAbsPC (PC);
515     }
516 }
517
518
519
520 static void OneLine (void)
521 /* Assemble one line */
522 {
523     Segment*      Seg   = 0;
524     unsigned long PC    = 0;
525     SymEntry*     Sym   = 0;
526     int           Macro = 0;
527     int           Instr = -1;
528
529     /* Initialize the new listing line if we are actually reading from file
530      * and not from internally pushed input.
531      */
532     if (!HavePushedInput ()) {
533         InitListingLine ();
534     }
535
536     if (Tok == TOK_COLON) {
537         /* An unnamed label */
538         ULabDef ();
539         NextTok ();
540     }
541
542     /* If the first token on the line is an identifier, check for a macro or
543      * an instruction.
544      */
545     if (Tok == TOK_IDENT) {
546         if (!UbiquitousIdents) {
547             /* Macros and symbols cannot use instruction names */
548             Instr = FindInstruction (SVal);
549             if (Instr < 0) {
550                 Macro = IsMacro (SVal);
551             }
552         } else {
553             /* Macros and symbols may use the names of instructions */
554             Macro = IsMacro (SVal);
555         }
556     }
557
558     /* Handle an identifier */
559     if (Tok == TOK_LOCAL_IDENT || (Tok == TOK_IDENT && Instr < 0 && !Macro)) {
560
561         /* Did we have whitespace before the ident? */
562         int HadWS = WS;
563
564         /* Generate the symbol table entry, then skip the name */
565         if (Tok == TOK_IDENT) {
566             Sym = SymFind (CurrentScope, SVal, SYM_ALLOC_NEW);
567         } else {
568             Sym = SymFindLocal (SymLast, SVal, SYM_ALLOC_NEW);
569         }
570         NextTok ();
571
572         /* If a colon follows, this is a label definition. If there
573          * is no colon, it's an assignment.
574          */
575         if (Tok == TOK_EQ || Tok == TOK_ASSIGN) {
576
577             /* Determine the symbol flags from the assignment token */
578             unsigned Flags = (Tok == TOK_ASSIGN)? SF_LABEL : SF_NONE;
579
580             /* Skip the '=' */
581             NextTok ();
582
583             /* Define the symbol with the expression following the '=' */
584             SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
585
586             /* Don't allow anything after a symbol definition */
587             ConsumeSep ();
588             return;
589
590         } else if (Tok == TOK_SET) {
591
592             ExprNode* Expr;
593
594             /* .SET defines variables (= redefinable symbols) */
595             NextTok ();
596
597             /* Read the assignment expression, which must be constant */
598             Expr = GenLiteralExpr (ConstExpression ());
599
600             /* Define the symbol with the constant expression following
601              * the '='
602              */
603             SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_VAR);
604
605             /* Don't allow anything after a symbol definition */
606             ConsumeSep ();
607             return;
608
609         } else {
610
611             /* A label. Remember the current segment, so we can later
612              * determine the size of the data stored under the label.
613              */
614             Seg = ActiveSeg;
615             PC  = GetPC ();
616
617             /* Define the label */
618             SymDef (Sym, GenCurrentPC (), ADDR_SIZE_DEFAULT, SF_LABEL);
619
620             /* Skip the colon. If NoColonLabels is enabled, allow labels
621              * without a colon if there is no whitespace before the
622              * identifier.
623              */
624             if (Tok != TOK_COLON) {
625                 if (HadWS || !NoColonLabels) {
626                     Error ("`:' expected");
627                     /* Try some smart error recovery */
628                     if (Tok == TOK_NAMESPACE) {
629                         NextTok ();
630                     }
631                 }
632             } else {
633                 /* Skip the colon */
634                 NextTok ();
635             }
636
637             /* If we come here, a new identifier may be waiting, which may
638              * be a macro or instruction.
639              */
640             if (Tok == TOK_IDENT) {
641                 if (!UbiquitousIdents) {
642                     /* Macros and symbols cannot use instruction names */
643                     Instr = FindInstruction (SVal);
644                     if (Instr < 0) {
645                         Macro = IsMacro (SVal);
646                     }
647                 } else {
648                     /* Macros and symbols may use the names of instructions */
649                     Macro = IsMacro (SVal);
650                 }
651             }
652         }
653     }
654
655     /* We've handled a possible label, now handle the remainder of the line */
656     if (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO) {
657         /* A control command */
658         HandlePseudo ();
659     } else if (Macro) {
660         /* A macro expansion */
661         MacExpandStart ();
662     } else if (Instr >= 0 ||
663                (UbiquitousIdents && ((Instr = FindInstruction (SVal)) >= 0))) {
664         /* A mnemonic - assemble one instruction */
665         HandleInstruction (Instr);
666     } else if (PCAssignment && (Tok == TOK_STAR || Tok == TOK_PC)) {
667         NextTok ();
668         if (Tok != TOK_EQ) {
669             Error ("`=' expected");
670             SkipUntilSep ();
671         } else {
672             /* Skip the equal sign */
673             NextTok ();
674             /* Enter absolute mode */
675             DoPCAssign ();
676         }
677     }
678
679     /* If we have defined a label, remember its size. Sym is also set by
680      * a symbol assignment, but in this case Done is false, so we don't
681      * come here.
682      */
683     if (Sym) {
684         unsigned long Size;
685         if (Seg == ActiveSeg) {
686             /* Same segment */
687             Size = GetPC () - PC;
688         } else {
689             /* The line has switched the segment */
690             Size = 0;
691         }
692         DefSizeOfSymbol (Sym, Size);
693     }
694
695     /* Line separator must come here */
696     ConsumeSep ();
697 }
698
699
700
701 static void Assemble (void)
702 /* Start the ball rolling ... */
703 {
704     /* Prime the pump */
705     NextTok ();
706
707     /* Assemble lines until end of file */
708     while (Tok != TOK_EOF) {
709         OneLine ();
710     }
711 }
712
713
714
715 static void CreateObjFile (void)
716 /* Create the object file */
717 {
718     /* Open the object, write the header */
719     ObjOpen ();
720
721     /* Write the object file options */
722     WriteOptions ();
723
724     /* Write the list of input files */
725     WriteFiles ();
726
727     /* Write the segment data to the file */
728     WriteSegments ();
729
730     /* Write the import list */
731     WriteImports ();
732
733     /* Write the export list */
734     WriteExports ();
735
736     /* Write debug symbols if requested */
737     WriteDbgSyms ();
738
739     /* Write line infos if requested */
740     WriteLineInfo ();
741
742     /* Write the string pool */
743     WriteStrPool ();
744
745     /* Write the assertions */
746     WriteAssertions ();
747
748     /* Write an updated header and close the file */
749     ObjClose ();
750 }
751
752
753
754 int main (int argc, char* argv [])
755 /* Assembler main program */
756 {
757     /* Program long options */
758     static const LongOpt OptTab[] = {
759         { "--auto-import",      0,      OptAutoImport           },
760         { "--cpu",              1,      OptCPU                  },
761         { "--debug-info",       0,      OptDebugInfo            },
762         { "--feature",          1,      OptFeature              },
763         { "--help",             0,      OptHelp                 },
764         { "--ignore-case",      0,      OptIgnoreCase           },
765         { "--include-dir",      1,      OptIncludeDir           },
766         { "--list-bytes",       1,      OptListBytes            },
767         { "--listing",          0,      OptListing              },
768         { "--macpack-dir",      1,      OptMacPackDir           },
769         { "--memory-model",     1,      OptMemoryModel          },
770         { "--pagelength",       1,      OptPageLength           },
771         { "--smart",            0,      OptSmart                },
772         { "--target",           1,      OptTarget               },
773         { "--verbose",          0,      OptVerbose              },
774         { "--version",          0,      OptVersion              },
775     };
776
777     unsigned I;
778
779     /* Initialize the cmdline module */
780     InitCmdLine (&argc, &argv, "ca65");
781
782     /* Enter the base lexical level. We must do that here, since we may
783      * define symbols using -D.
784      */
785     SymEnterLevel ("", ST_GLOBAL, ADDR_SIZE_DEFAULT);
786
787     /* Check the parameters */
788     I = 1;
789     while (I < ArgCount) {
790
791         /* Get the argument */
792         const char* Arg = ArgVec [I];
793
794         /* Check for an option */
795         if (Arg[0] == '-') {
796             switch (Arg[1]) {
797
798                 case '-':
799                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
800                     break;
801
802                 case 'g':
803                     OptDebugInfo (Arg, 0);
804                     break;
805
806                 case 'h':
807                     OptHelp (Arg, 0);
808                     break;
809
810                 case 'i':
811                     OptIgnoreCase (Arg, 0);
812                     break;
813
814                 case 'l':
815                     OptListing (Arg, 0);
816                     break;
817
818                 case 'm':
819                     if (Arg[2] == 'm') {
820                         OptMemoryModel (Arg, GetArg (&I, 3));
821                     } else {
822                         UnknownOption (Arg);
823                     }
824                     break;
825
826                 case 'o':
827                     OutFile = GetArg (&I, 2);
828                     break;
829
830                 case 's':
831                     OptSmart (Arg, 0);
832                     break;
833
834                 case 't':
835                     OptTarget (Arg, GetArg (&I, 2));
836                     break;
837
838                 case 'v':
839                     OptVerbose (Arg, 0);
840                     break;
841
842                 case 'D':
843                     DefineSymbol (GetArg (&I, 2));
844                     break;
845
846                 case 'I':
847                     OptIncludeDir (Arg, GetArg (&I, 2));
848                     break;
849
850                 case 'U':
851                     OptAutoImport (Arg, 0);
852                     break;
853
854                 case 'V':
855                     OptVersion (Arg, 0);
856                     break;
857
858                 case 'W':
859                     WarnLevel = atoi (GetArg (&I, 2));
860                     break;
861
862                 default:
863                     UnknownOption (Arg);
864                     break;
865
866             }
867         } else {
868             /* Filename. Check if we already had one */
869             if (InFile) {
870                 fprintf (stderr, "%s: Don't know what to do with `%s'\n",
871                          ProgName, Arg);
872                 exit (EXIT_FAILURE);
873             } else {
874                 InFile = Arg;
875             }
876         }
877
878         /* Next argument */
879         ++I;
880     }
881
882     /* Do we have an input file? */
883     if (InFile == 0) {
884         fprintf (stderr, "%s: No input files\n", ProgName);
885         exit (EXIT_FAILURE);
886     }
887
888     /* If no CPU given, use the default CPU for the target */
889     if (GetCPU () == CPU_UNKNOWN) {
890         if (Target != TGT_UNKNOWN) {
891             SetCPU (DefaultCPU[Target]);
892         } else {
893             SetCPU (CPU_6502);
894         }
895     }
896
897     /* If no memory model was given, use the default */
898     if (MemoryModel == MMODEL_UNKNOWN) {
899         SetMemoryModel (MMODEL_NEAR);
900     }
901
902     /* Initialize the segments */
903     InitSegments ();
904
905     /* Initialize the scanner, open the input file */
906     InitScanner (InFile);
907
908     /* Define the default options */
909     SetOptions ();
910
911     /* Assemble the input */
912     Assemble ();
913
914     /* If we didn't have any errors, check the segment stack */
915     if (ErrorCount == 0) {
916         SegStackCheck ();
917     }
918
919     /* If we didn't have any errors, check the unnamed labels */
920     if (ErrorCount == 0) {
921         ULabCheck ();
922     }
923
924     /* If we didn't have any errors, check the symbol table */
925     if (ErrorCount == 0) {
926         SymCheck ();
927     }
928
929     /* If we didn't have any errors, check and resolve the segment data */
930     if (ErrorCount == 0) {
931         SegCheck ();
932     }
933
934     /* If we didn't have any errors, check the assertions */
935     if (ErrorCount == 0) {
936         CheckAssertions ();
937     }
938
939     /* If we didn't have an errors, index the line infos */
940     MakeLineInfoIndex ();
941
942     /* Dump the data */
943     if (Verbosity >= 2) {
944         SymDump (stdout);
945         SegDump ();
946     }
947
948     /* If we didn't have any errors, create the object and listing files */
949     if (ErrorCount == 0) {
950         CreateObjFile ();
951         if (Listing) {
952             CreateListing ();
953         }
954     }
955
956     /* Close the input file */
957     DoneScanner ();
958
959     /* Return an apropriate exit code */
960     return (ErrorCount == 0)? EXIT_SUCCESS : EXIT_FAILURE;
961 }
962
963
964