]> git.sur5r.net Git - cc65/blob - ca65/main.c
Fixed _textcolor definition.
[cc65] / ca65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                 Main program for the ca65 macroassembler                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 <ctype.h>
40 #include <time.h>
41
42 #include "../common/version.h"
43
44 #include "error.h"
45 #include "expr.h"
46 #include "global.h"
47 #include "incpath.h"
48 #include "instr.h"
49 #include "listing.h"
50 #include "macro.h"
51 #include "mem.h"
52 #include "objcode.h"
53 #include "objfile.h"
54 #include "options.h"
55 #include "pseudo.h"
56 #include "scanner.h"
57 #include "symtab.h"
58 #include "ulabel.h"
59
60
61
62 /*****************************************************************************/
63 /*                                   Code                                    */
64 /*****************************************************************************/
65
66
67
68 static void Usage (void)
69 /* Print usage information and exit */
70 {
71     fprintf (stderr,
72              "Usage: %s [options] file\n"
73              "Short options:\n"
74              "  -g\t\t\tAdd debug info to object file\n"
75              "  -i\t\t\tIgnore case of symbols\n"
76              "  -l\t\t\tCreate a listing if assembly was ok\n"
77              "  -o name\t\tName the output file\n"
78              "  -s\t\t\tEnable smart mode\n"
79              "  -v\t\t\tIncrease verbosity\n"
80              "  -D name[=value]\tDefine a symbol\n"
81              "  -I dir\t\tSet an include directory search path\n"
82              "  -U\t\t\tMark unresolved symbols as import\n"
83              "  -V\t\t\tPrint the assembler version\n"
84              "  -W n\t\t\tSet warning level n\n"
85              "\n"
86              "Long options:\n"
87              "  --auto-import\t\tMark unresolved symbols as import\n"
88              "  --cpu type\t\tSet cpu type\n"
89              "  --debug-info\t\tAdd debug info to object file\n"
90              "  --ignore-case\t\tIgnore case of symbols\n"
91              "  --include-dir dir\tSet an include directory search path\n"
92              "  --listing\t\tCreate a listing if assembly was ok\n"
93              "  --pagelength n\tSet the page length for the listing\n"
94              "  --smart\t\tEnable smart mode\n"
95              "  --verbose\t\tIncrease verbosity\n"
96              "  --version\t\tPrint the assembler version\n",
97              ProgName);
98     exit (EXIT_FAILURE);
99 }
100
101
102
103 static void UnknownOption (const char* Arg)
104 /* Print an error about an unknown option. Print usage information and exit */
105 {
106     fprintf (stderr, "Unknown option: %s\n", Arg);
107     Usage ();
108 }
109
110
111
112 static void NeedArg (const char* Arg)
113 /* Print an error about a missing option argument and exit. */
114 {
115     fprintf (stderr, "Option requires an argument: %s\n", Arg);
116     exit (EXIT_FAILURE);
117 }
118
119
120
121 static void InvSym (const char* Def)
122 /* Print an error about an invalid symbol definition and die */
123 {
124     fprintf (stderr, "Invalid symbol definition: `%s'\n", Def);
125     exit (EXIT_FAILURE);
126 }
127
128
129
130 static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
131 /* Get an option argument */
132 {
133     const char* Arg = argv [*ArgNum];
134     if (Arg [Len] != '\0') {
135         /* Argument appended */
136         return Arg + Len;
137     } else {
138         /* Separate argument */
139         Arg = argv [*ArgNum + 1];
140         if (Arg == 0) {
141             /* End of arguments */
142             NeedArg (argv [*ArgNum]);
143         }
144         ++(*ArgNum);
145         return Arg;
146     }
147 }
148
149
150
151 static void SetOptions (void)
152 /* Set the option for the translator */
153 {
154     char Buf [256];
155
156     /* Set the translator */
157     sprintf (Buf, "ca65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
158     OptTranslator (Buf);
159
160     /* Set date and time */
161     OptDateTime ((unsigned long) time(0));
162 }
163
164
165
166 static void DefineSymbol (const char* Def)
167 /* Define a symbol from the command line */
168 {
169     const char* P;
170     unsigned I;
171     long Val;
172     char SymName [MAX_STR_LEN+1];
173
174     /* The symbol must start with a character or underline */
175     if (Def [0] != '_' && !isalpha (Def [0])) {
176         InvSym (Def);
177     }
178     P = Def;
179
180     /* Copy the symbol, checking the rest */
181     I = 0;
182     while (isalnum (*P) || *P == '_') {
183         if (I <= MAX_STR_LEN) {
184             SymName [I++] = *P;
185         }
186         ++P;
187     }
188     SymName [I] = '\0';
189
190     /* Do we have a value given? */
191     if (*P != '=') {
192         if (*P != '\0') {
193             InvSym (Def);
194         }
195         Val = 0;
196     } else {
197         /* We have a value */
198         ++P;
199         if (*P == '$') {
200             ++P;
201             if (sscanf (P, "%lx", &Val) != 1) {
202                 InvSym (Def);
203             }
204         } else {
205             if (sscanf (P, "%li", &Val) != 1) {
206                 InvSym (Def);
207             }
208         }
209     }
210
211     /* Check if have already a symbol with this name */
212     if (SymIsDef (SymName)) {
213         fprintf (stderr, "`%s' is already defined\n", SymName);
214         exit (EXIT_FAILURE);
215     }
216
217     /* Define the symbol */
218     SymDef (SymName, LiteralExpr (Val), 0);
219 }
220
221
222
223 static void OptAutoImport (const char* Opt)
224 /* Mark unresolved symbols as imported */
225 {
226     AutoImport = 1;
227 }
228
229
230
231 static void OptCPU (const char* Opt, const char* Arg)
232 /* Handle the --cpu option */
233 {
234     if (Arg == 0) {
235         NeedArg (Opt);
236     }
237     if (strcmp (Arg, "6502") == 0) {
238         SetCPU (CPU_6502);
239     } else if (strcmp (Arg, "65C02") == 0) {
240         SetCPU (CPU_65C02);
241     } else if (strcmp (Arg, "65816") == 0) {
242         SetCPU (CPU_65816);
243 #ifdef SUNPLUS
244     } else if (strcmp (Arg, "sunplus") == 0) {
245         SetCPU (CPU_SUNPLUS);
246 #endif
247     } else {
248         fprintf (stderr, "Invalid CPU: `%s'\n", Arg);
249         exit (EXIT_FAILURE);
250     }
251 }
252
253
254
255 static void OptDebugInfo (const char* Opt)
256 /* Add debug info to the object file */
257 {
258     DbgSyms = 1;
259 }
260
261
262
263 static void OptIgnoreCase (const char* Opt)
264 /* Ignore case on symbols */
265 {
266     IgnoreCase = 1;
267 }
268
269
270
271 static void OptIncludeDir (const char* Opt, const char* Arg)
272 /* Add an include search path */
273 {
274     if (Arg == 0) {
275         NeedArg (Opt);
276     }
277     AddIncludePath (Arg);
278 }
279
280
281
282 static void OptListing (const char* Opt)
283 /* Create a listing file */
284 {
285     Listing = 1;
286 }
287
288
289
290 static void OptPageLength (const char* Opt, const char* Arg)
291 /* Handle the --pagelength option */
292 {
293     int Len;
294     if (Arg == 0) {
295         NeedArg (Opt);
296     }
297     Len = atoi (Arg);
298     if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
299         fprintf (stderr, "Invalid page length: %d\n", Len);
300         exit (EXIT_FAILURE);
301     }
302     PageLength = Len;
303 }
304
305
306
307 static void OptSmart (const char* Opt)
308 /* Handle the -s/--smart options */
309 {
310     SmartMode = 1;
311 }
312
313
314
315 static void OptVerbose (const char* Opt)
316 /* Increase verbosity */
317 {
318     ++Verbose;
319 }
320
321
322
323 static void OptVersion (const char* Opt)
324 /* Print the assembler version */
325 {
326     fprintf (stderr,
327              "ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
328              VER_MAJOR, VER_MINOR, VER_PATCH);
329 }
330
331
332
333 static void LongOption (int* ArgNum, char* argv [])
334 /* Handle a long command line option */
335 {
336     const char* Opt = argv [*ArgNum];
337     const char* Arg = argv [*ArgNum+1];
338
339     if (strcmp (Opt, "--auto-import") == 0) {
340         OptAutoImport (Opt);
341     } else if (strcmp (Opt, "--cpu") == 0) {
342         OptCPU (Opt, Arg);
343         ++(*ArgNum);
344     } else if (strcmp (Opt, "--debug-info") == 0) {
345         OptIgnoreCase (Opt);
346     } else if (strcmp (Opt, "--ignore-case") == 0) {
347         OptIgnoreCase (Opt);
348     } else if (strcmp (Opt, "--include-dir") == 0) {
349         OptIncludeDir (Opt, Arg);
350         ++(*ArgNum);
351     } else if (strcmp (Opt, "--listing") == 0) {
352         OptListing (Opt);
353     } else if (strcmp (Opt, "--pagelength") == 0) {
354         OptPageLength (Opt, Arg);
355         ++(*ArgNum);
356     } else if (strcmp (Opt, "--smart") == 0) {
357         OptSmart (Opt);
358     } else if (strcmp (Opt, "--verbose") == 0) {
359         OptVerbose (Opt);
360     } else if (strcmp (Opt, "--version") == 0) {
361         OptVersion (Opt);
362     } else {
363         UnknownOption (Opt);
364     }
365 }
366
367
368
369 static void OneLine (void)
370 /* Assemble one line */
371 {
372     char Ident [MAX_STR_LEN+1];
373     int Done = 0;
374
375     /* Initialize the listing line */
376     InitListingLine ();
377
378     if (Tok == TOK_COLON) {
379         /* An unnamed label */
380         ULabDef ();
381         NextTok ();
382     }
383
384     /* Assemble the line */
385     if (Tok == TOK_IDENT) {
386
387         /* Is it a macro? */
388         if (IsMacro (SVal)) {
389
390             /* Yes, start a macro expansion */
391             MacExpandStart ();
392             Done = 1;
393
394         } else {
395
396             /* No, label. Remember the identifier, then skip it */
397             int HadWS = WS;     /* Did we have whitespace before the ident? */
398             strcpy (Ident, SVal);
399             NextTok ();
400
401             /* If a colon follows, this is a label definition. If there
402              * is no colon, it's an assignment.
403              */
404             if (Tok == TOK_EQ) {
405                 /* Skip the '=' */
406                 NextTok ();
407                 /* Define the symbol with the expression following the
408                  * '='
409                  */
410                 SymDef (Ident, Expression (), 0);
411                 /* Don't allow anything after a symbol definition */
412                 Done = 1;
413             } else {
414                 /* Define a label */
415                 SymDef (Ident, CurrentPC (), IsZPSeg ());
416                 /* Skip the colon. If NoColonLabels is enabled, allow labels
417                  * without a colon if there is no whitespace before the
418                  * identifier.
419                  */
420                 if (Tok != TOK_COLON) {
421                     if (HadWS || !NoColonLabels) {
422                         Error (ERR_COLON_EXPECTED);
423                     }
424                     if (Tok == TOK_NAMESPACE) {
425                         /* Smart :: handling */
426                         NextTok ();
427                     }
428                 } else {
429                     /* Skip the colon */
430                     NextTok ();
431                 }
432             }
433         }
434     }
435
436     if (!Done) {
437
438         if (TokIsPseudo (Tok)) {
439             /* A control command, IVal is index into table */
440             HandlePseudo ();
441         } else if (Tok == TOK_MNEMO) {
442             /* A mnemonic - assemble one instruction */
443             HandleInstruction (IVal);
444         } else if (Tok == TOK_IDENT && IsMacro (SVal)) {
445             /* A macro expansion */
446             MacExpandStart ();
447         }
448     }
449
450     /* Calling InitListingLine again here is part of a hack that introduces
451      * enough magic to make the PC output in the listing work.
452      */
453     InitListingLine ();
454
455     /* Line separator must come here */
456     ConsumeSep ();
457 }
458
459
460
461 static void Assemble (void)
462 /* Start the ball rolling ... */
463 {
464     /* Prime the pump */
465     NextTok ();
466
467     /* Assemble lines until end of file */
468     while (Tok != TOK_EOF) {
469         OneLine ();
470     }
471 }
472
473
474
475 static void CreateObjFile (void)
476 /* Create the object file */
477 {
478     /* Open the object, write the header */
479     ObjOpen ();
480
481     /* Write the object file options */
482     WriteOptions ();
483
484     /* Write the list of input files */
485     WriteFiles ();
486
487     /* Write the segment data to the file */
488     WriteSegments ();
489
490     /* Write the import list */
491     WriteImports ();
492
493     /* Write the export list */
494     WriteExports ();
495
496     /* Write debug symbols if requested */
497     WriteDbgSyms ();
498
499     /* Write an updated header and close the file */
500     ObjClose ();
501 }
502
503
504
505 int main (int argc, char* argv [])
506 /* Assembler main program */
507 {
508     int I;
509
510     /* Set the program name */
511     ProgName = argv [0];
512
513     /* We must have a file name */
514     if (argc < 2) {
515         Usage ();
516     }
517
518     /* Enter the base lexical level. We must do that here, since we may
519      * define symbols using -D.
520      */
521     SymEnterLevel ();
522
523     /* Check the parameters */
524     I = 1;
525     while (I < argc) {
526
527         /* Get the argument */
528         const char* Arg = argv [I];
529
530         /* Check for an option */
531         if (Arg [0] == '-') {
532             switch (Arg [1]) {
533
534                 case '-':
535                     LongOption (&I, argv);
536                     break;
537
538                 case 'g':
539                     OptDebugInfo (Arg);
540                     break;
541
542                 case 'i':
543                     OptIgnoreCase (Arg);
544                     break;
545
546                 case 'l':     
547                     OptListing (Arg);
548                     break;
549
550                 case 'o':
551                     OutFile = GetArg (&I, argv, 2);
552                     break;
553
554                 case 's':
555                     OptSmart (Arg);
556                     break;
557
558                 case 'v':
559                     OptVerbose (Arg);
560                     break;
561
562                 case 'D':
563                     DefineSymbol (GetArg (&I, argv, 2));
564                     break;
565
566                 case 'I':
567                     OptIncludeDir (Arg, GetArg (&I, argv, 2));
568                     break;
569
570                 case 'U':
571                     OptAutoImport (Arg);
572                     break;
573
574                 case 'V':
575                     OptVersion (Arg);
576                     break;
577
578                 case 'W':
579                     WarnLevel = atoi (GetArg (&I, argv, 2));
580                     break;
581
582                 default:
583                     UnknownOption (Arg);
584                     break;
585
586             }
587         } else {
588             /* Filename. Check if we already had one */
589             if (InFile) {
590                 fprintf (stderr, "Don't know what to do with `%s'\n", Arg);
591                 Usage ();
592             } else {
593                 InFile = Arg;
594             }
595         }
596
597         /* Next argument */
598         ++I;
599     }
600
601     /* Do we have an input file? */
602     if (InFile == 0) {
603         fprintf (stderr, "No input file\n");
604         exit (EXIT_FAILURE);
605     }
606
607     /* Initialize the scanner, open the input file */
608     InitScanner (InFile);
609
610     /* Define the default options */
611     SetOptions ();
612
613     /* Assemble the input */
614     Assemble ();
615
616     /* If we didn't have any errors, check the unnamed labels */
617     if (ErrorCount == 0) {
618         ULabCheck ();
619     }
620
621     /* If we didn't have any errors, check the symbol table */
622     if (ErrorCount == 0) {
623         SymCheck ();
624     }
625
626     /* If we didn't have any errors, check and resolve the segment data */
627     if (ErrorCount == 0) {
628         SegCheck ();
629     }
630
631     /* Dump the data */
632     if (Verbose >= 2) {
633         SymDump (stdout);
634         SegDump ();
635     }
636
637     /* If we didn't have any errors, create the object and listing files */
638     if (ErrorCount == 0) {
639         CreateObjFile ();
640         if (Listing) {
641             CreateListing ();
642         }
643     }
644
645     /* Close the input file */
646     DoneScanner ();
647
648     /* Return an apropriate exit code */
649     return (ErrorCount == 0)? EXIT_SUCCESS : EXIT_FAILURE;
650 }
651
652
653