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