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