]> git.sur5r.net Git - cc65/blob - src/ca65/main.c
Maintain some additional information for scopes. Write a dummy scope section
[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         Sym = ParseAnySymName (SYM_ALLOC_NEW);
636
637         /* If a colon follows, this is a label definition. If there
638          * is no colon, it's an assignment.
639          */
640         if (Tok == TOK_EQ || Tok == TOK_ASSIGN) {
641
642             /* Determine the symbol flags from the assignment token */
643             unsigned Flags = (Tok == TOK_ASSIGN)? SF_LABEL : SF_NONE;
644
645             /* Skip the '=' */
646             NextTok ();
647
648             /* Define the symbol with the expression following the '=' */
649             SymDef (Sym, Expression(), ADDR_SIZE_DEFAULT, Flags);
650
651             /* Don't allow anything after a symbol definition */
652             ConsumeSep ();
653             return;
654
655         } else if (Tok == TOK_SET) {
656
657             ExprNode* Expr;
658
659             /* .SET defines variables (= redefinable symbols) */
660             NextTok ();
661
662             /* Read the assignment expression, which must be constant */
663             Expr = GenLiteralExpr (ConstExpression ());
664
665             /* Define the symbol with the constant expression following
666              * the '='
667              */
668             SymDef (Sym, Expr, ADDR_SIZE_DEFAULT, SF_VAR);
669
670             /* Don't allow anything after a symbol definition */
671             ConsumeSep ();
672             return;
673
674         } else {
675
676             /* A label. Remember the current segment, so we can later
677              * determine the size of the data stored under the label.
678              */
679             Seg = ActiveSeg;
680             PC  = GetPC ();
681
682             /* Define the label */
683             SymDef (Sym, GenCurrentPC (), ADDR_SIZE_DEFAULT, SF_LABEL);
684
685             /* Skip the colon. If NoColonLabels is enabled, allow labels
686              * without a colon if there is no whitespace before the
687              * identifier.
688              */
689             if (Tok != TOK_COLON) {
690                 if (HadWS || !NoColonLabels) {
691                     Error ("`:' expected");
692                     /* Try some smart error recovery */
693                     if (Tok == TOK_NAMESPACE) {
694                         NextTok ();
695                     }
696                 }
697             } else {
698                 /* Skip the colon */
699                 NextTok ();
700             }
701
702             /* If we come here, a new identifier may be waiting, which may
703              * be a macro or instruction.
704              */
705             if (Tok == TOK_IDENT) {
706                 if (!UbiquitousIdents) {
707                     /* Macros and symbols cannot use instruction names */
708                     Instr = FindInstruction (&SVal);
709                     if (Instr < 0) {
710                         Macro = IsMacro (&SVal);
711                     }
712                 } else {
713                     /* Macros and symbols may use the names of instructions */
714                     Macro = IsMacro (&SVal);
715                 }
716             }
717         }
718     }
719
720     /* We've handled a possible label, now handle the remainder of the line */
721     if (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO) {
722         /* A control command */
723         HandlePseudo ();
724     } else if (Macro) {
725         /* A macro expansion */
726         MacExpandStart ();
727     } else if (Instr >= 0 ||
728                (UbiquitousIdents && ((Instr = FindInstruction (&SVal)) >= 0))) {
729         /* A mnemonic - assemble one instruction */
730         HandleInstruction (Instr);
731     } else if (PCAssignment && (Tok == TOK_STAR || Tok == TOK_PC)) {
732         NextTok ();
733         if (Tok != TOK_EQ) {
734             Error ("`=' expected");
735             SkipUntilSep ();
736         } else {
737             /* Skip the equal sign */
738             NextTok ();
739             /* Enter absolute mode */
740             DoPCAssign ();
741         }
742     }
743
744     /* If we have defined a label, remember its size. Sym is also set by
745      * a symbol assignment, but in this case Done is false, so we don't
746      * come here.
747      */
748     if (Sym) {
749         unsigned long Size;
750         if (Seg == ActiveSeg) {
751             /* Same segment */
752             Size = GetPC () - PC;
753         } else {
754             /* The line has switched the segment */
755             Size = 0;
756         }
757         DefSizeOfSymbol (Sym, Size);
758     }
759
760     /* Line separator must come here */
761     ConsumeSep ();
762 }
763
764
765
766 static void Assemble (void)
767 /* Start the ball rolling ... */
768 {
769     /* Prime the pump */
770     NextTok ();
771
772     /* Assemble lines until end of file */
773     while (Tok != TOK_EOF) {
774         OneLine ();
775     }
776 }
777
778
779
780 static void CreateObjFile (void)
781 /* Create the object file */
782 {
783     /* Open the object, write the header */
784     ObjOpen ();
785
786     /* Write the object file options */
787     WriteOptions ();
788
789     /* Write the list of input files */
790     WriteFiles ();
791
792     /* Write the segment data to the file */
793     WriteSegments ();
794
795     /* Write the import list */
796     WriteImports ();
797
798     /* Write the export list */
799     WriteExports ();
800
801     /* Write the scopes if requested */
802     WriteScopes ();
803
804     /* Write debug symbols if requested */
805     WriteDbgSyms ();
806
807     /* Write line infos if requested */
808     WriteLineInfo ();
809
810     /* Write the string pool */
811     WriteStrPool ();
812
813     /* Write the assertions */
814     WriteAssertions ();
815
816     /* Write an updated header and close the file */
817     ObjClose ();
818 }
819
820
821
822 int main (int argc, char* argv [])
823 /* Assembler main program */
824 {
825     /* Program long options */
826     static const LongOpt OptTab[] = {
827         { "--auto-import",      0,      OptAutoImport           },
828         { "--bin-include-dir",  1,      OptBinIncludeDir        },
829         { "--cpu",              1,      OptCPU                  },
830         { "--create-dep",       1,      OptCreateDep            },
831         { "--create-full-dep",  1,      OptCreateFullDep        },
832         { "--debug-info",       0,      OptDebugInfo            },
833         { "--feature",          1,      OptFeature              },
834         { "--forget-inc-paths", 0,      OptForgetIncPaths       },
835         { "--help",             0,      OptHelp                 },
836         { "--ignore-case",      0,      OptIgnoreCase           },
837         { "--include-dir",      1,      OptIncludeDir           },
838         { "--list-bytes",       1,      OptListBytes            },
839         { "--listing",          0,      OptListing              },
840         { "--macpack-dir",      1,      OptMacPackDir           },
841         { "--memory-model",     1,      OptMemoryModel          },
842         { "--pagelength",       1,      OptPageLength           },
843         { "--smart",            0,      OptSmart                },
844         { "--target",           1,      OptTarget               },
845         { "--verbose",          0,      OptVerbose              },
846         { "--version",          0,      OptVersion              },
847     };
848
849     /* Name of the global name space */
850     static const StrBuf GlobalNameSpace = STATIC_STRBUF_INITIALIZER;
851
852     unsigned I;
853
854     /* Initialize the cmdline module */
855     InitCmdLine (&argc, &argv, "ca65");
856
857     /* Initialize the include search paths */
858     InitIncludePaths ();
859
860     /* Enter the base lexical level. We must do that here, since we may
861      * define symbols using -D.
862      */
863     SymEnterLevel (&GlobalNameSpace, ST_GLOBAL, ADDR_SIZE_DEFAULT);
864
865     /* Check the parameters */
866     I = 1;
867     while (I < ArgCount) {
868
869         /* Get the argument */
870         const char* Arg = ArgVec [I];
871
872         /* Check for an option */
873         if (Arg[0] == '-') {
874             switch (Arg[1]) {
875
876                 case '-':
877                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
878                     break;
879
880                 case 'g':
881                     OptDebugInfo (Arg, 0);
882                     break;
883
884                 case 'h':
885                     OptHelp (Arg, 0);
886                     break;
887
888                 case 'i':
889                     OptIgnoreCase (Arg, 0);
890                     break;
891
892                 case 'l':
893                     OptListing (Arg, 0);
894                     break;
895
896                 case 'm':
897                     if (Arg[2] == 'm') {
898                         OptMemoryModel (Arg, GetArg (&I, 3));
899                     } else {
900                         UnknownOption (Arg);
901                     }
902                     break;
903
904                 case 'o':
905                     OutFile = GetArg (&I, 2);
906                     break;
907
908                 case 's':
909                     OptSmart (Arg, 0);
910                     break;
911
912                 case 't':
913                     OptTarget (Arg, GetArg (&I, 2));
914                     break;
915
916                 case 'v':
917                     OptVerbose (Arg, 0);
918                     break;
919
920                 case 'D':
921                     DefineSymbol (GetArg (&I, 2));
922                     break;
923
924                 case 'I':
925                     OptIncludeDir (Arg, GetArg (&I, 2));
926                     break;
927
928                 case 'U':
929                     OptAutoImport (Arg, 0);
930                     break;
931
932                 case 'V':
933                     OptVersion (Arg, 0);
934                     break;
935
936                 case 'W':
937                     WarnLevel = atoi (GetArg (&I, 2));
938                     break;
939
940                 default:
941                     UnknownOption (Arg);
942                     break;
943
944             }
945         } else {
946             /* Filename. Check if we already had one */
947             if (InFile) {
948                 fprintf (stderr, "%s: Don't know what to do with `%s'\n",
949                          ProgName, Arg);
950                 exit (EXIT_FAILURE);
951             } else {
952                 InFile = Arg;
953             }
954         }
955
956         /* Next argument */
957         ++I;
958     }
959
960     /* Do we have an input file? */
961     if (InFile == 0) {
962         fprintf (stderr, "%s: No input files\n", ProgName);
963         exit (EXIT_FAILURE);
964     }
965
966     /* If no CPU given, use the default CPU for the target */
967     if (GetCPU () == CPU_UNKNOWN) {
968         if (Target != TGT_UNKNOWN) {
969             SetCPU (DefaultCPU[Target]);
970         } else {
971             SetCPU (CPU_6502);
972         }
973     }
974
975     /* If no memory model was given, use the default */
976     if (MemoryModel == MMODEL_UNKNOWN) {
977         SetMemoryModel (MMODEL_NEAR);
978     }
979
980     /* Initialize the segments */
981     InitSegments ();
982
983     /* Initialize the scanner, open the input file */
984     InitScanner (InFile);
985
986     /* Define the default options */
987     SetOptions ();
988
989     /* Assemble the input */
990     Assemble ();
991
992     /* If we didn't have any errors, check the pseudo insn stacks */
993     if (ErrorCount == 0) {
994         CheckPseudo ();
995     }
996
997     /* If we didn't have any errors, check the unnamed labels */
998     if (ErrorCount == 0) {
999         ULabCheck ();
1000     }
1001
1002     /* If we didn't have any errors, check the symbol table */
1003     if (ErrorCount == 0) {
1004         SymCheck ();
1005     }
1006
1007     /* If we didn't have any errors, check and resolve the segment data */
1008     if (ErrorCount == 0) {
1009         SegCheck ();
1010     }
1011
1012     /* If we didn't have any errors, check the assertions */
1013     if (ErrorCount == 0) {
1014         CheckAssertions ();
1015     }
1016
1017     /* If we didn't have an errors, index the line infos */
1018     MakeLineInfoIndex ();
1019
1020     /* Dump the data */
1021     if (Verbosity >= 2) {
1022         SymDump (stdout);
1023         SegDump ();
1024     }
1025
1026     /* If we didn't have any errors, create the object, listing and
1027      * dependency files
1028      */
1029     if (ErrorCount == 0) {
1030         CreateObjFile ();
1031         if (Listing) {
1032             CreateListing ();
1033         }
1034        CreateDependencies ();
1035     }
1036
1037     /* Close the input file */
1038     DoneScanner ();
1039
1040     /* Return an apropriate exit code */
1041     return (ErrorCount == 0)? EXIT_SUCCESS : EXIT_FAILURE;
1042 }
1043
1044
1045