]> git.sur5r.net Git - cc65/blob - src/cc65/main.c
Rewrote the input file management.
[cc65] / src / cc65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                             cc65 main program                             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 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 <string.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #include <errno.h>
41
42 /* common */
43 #include "abend.h"
44 #include "cmdline.h"
45 #include "fname.h"
46 #include "target.h"
47 #include "version.h"
48 #include "xmalloc.h"
49
50 /* cc65 */
51 #include "asmcode.h"
52 #include "compile.h"
53 #include "cpu.h"
54 #include "error.h"
55 #include "global.h"
56 #include "incpath.h"
57 #include "input.h"
58 #include "macrotab.h"
59 #include "optimize.h"
60 #include "scanner.h"
61 #include "segname.h"
62
63
64
65 /*****************************************************************************/
66 /*                                   Code                                    */
67 /*****************************************************************************/
68
69
70
71 static void Usage (void)
72 {
73     fprintf (stderr,
74              "Usage: %s [options] file\n"
75              "Short options:\n"
76              "  -d\t\t\tDebug mode\n"
77              "  -g\t\t\tAdd debug info to object file\n"
78              "  -h\t\t\tHelp (this text)\n"
79              "  -j\t\t\tDefault characters are signed\n"
80              "  -o name\t\tName the output file\n"
81              "  -t sys\t\tSet the target system\n"
82              "  -v\t\t\tIncrease verbosity\n"
83              "  -A\t\t\tStrict ANSI mode\n"
84              "  -Cl\t\t\tMake local variables static\n"
85              "  -Dsym[=defn]\t\tDefine a symbol\n"
86              "  -I dir\t\tSet an include directory search path\n"
87              "  -O\t\t\tOptimize code\n"
88              "  -Oi\t\t\tOptimize code, inline more code\n"
89              "  -Or\t\t\tEnable register variables\n"
90              "  -Os\t\t\tInline some known functions\n"
91              "  -T\t\t\tInclude source as comment\n"
92              "  -V\t\t\tPrint the compiler version number\n"
93              "  -W\t\t\tSuppress warnings\n"
94              "\n"
95              "Long options:\n"
96              "  --ansi\t\tStrict ANSI mode\n"
97              "  --bss-name seg\tSet the name of the BSS segment\n"
98              "  --code-name seg\tSet the name of the CODE segment\n"
99              "  --cpu type\t\tSet cpu type\n"
100              "  --data-name seg\tSet the name of the DATA segment\n"
101              "  --debug\t\tDebug mode\n"
102              "  --debug-info\t\tAdd debug info to object file\n"
103              "  --help\t\tHelp (this text)\n"
104              "  --include-dir dir\tSet an include directory search path\n"
105              "  --rodata-name seg\tSet the name of the RODATA segment\n"
106              "  --signed-chars\tDefault characters are signed\n"
107              "  --static-locals\tMake local variables static\n"
108              "  --target sys\t\tSet the target system\n"
109              "  --verbose\t\tIncrease verbosity\n"
110              "  --version\t\tPrint the compiler version number\n",
111              ProgName);
112 }
113
114
115
116 static void cbmsys (const char* sys)
117 /* Define a CBM system */
118 {
119     AddNumericMacro ("__CBM__", 1);
120     AddNumericMacro (sys, 1);
121 }
122
123
124
125 static void SetSys (const char* Sys)
126 /* Define a target system */
127 {
128     switch (Target = FindTarget (Sys)) {
129
130         case TGT_NONE:
131             break;
132
133         case TGT_ATARI:
134             AddNumericMacro ("__ATARI__", 1);
135             break;
136
137         case TGT_C64:
138             cbmsys ("__C64__");
139             break;
140
141         case TGT_C128:
142             cbmsys ("__C128__");
143             break;
144
145         case TGT_ACE:
146             cbmsys ("__ACE__");
147             break;
148
149         case TGT_PLUS4:
150             cbmsys ("__PLUS4__");
151             break;
152
153         case TGT_CBM610:
154             cbmsys ("__CBM610__");
155             break;
156
157         case TGT_PET:
158             cbmsys ("__PET__");
159             break;
160
161         case TGT_NES:
162             AddNumericMacro ("__NES__", 1);
163             break;
164
165         case TGT_APPLE2:
166             AddNumericMacro ("__APPLE2__", 1);
167             break;
168
169         case TGT_GEOS:
170             /* Do not handle as a CBM system */
171             AddNumericMacro ("__GEOS__", 1);
172             break;
173
174         default:
175             AbEnd ("Unknown target system type");
176     }
177 }
178
179
180
181 static void DoCreateDep (const char* OutputName)
182 /* Create the dependency file */
183 {
184     /* Make the dependency file name from the output file name */
185     char* DepName = MakeFilename (OutputName, ".u");
186
187     /* Open the file */
188     FILE* F = fopen (DepName, "w");
189     if (F == 0) {
190         Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
191     }
192
193     /* Write the dependencies to the file */
194     WriteDependencies (F, OutputName);
195
196     /* Close the file, check for errors */
197     if (fclose (F) != 0) {
198         remove (DepName);
199         Fatal (FAT_CANNOT_WRITE_OUTPUT);
200     }
201
202     /* Free the name */
203     xfree (DepName);
204 }
205
206
207
208 static void DefineSym (const char* Def)
209 /* Define a symbol on the command line */
210 {
211     const char* P = Def;
212
213     /* The symbol must start with a character or underline */
214     if (Def [0] != '_' && !isalpha (Def [0])) {
215         InvDef (Def);
216     }
217
218     /* Check the symbol name */
219     while (isalnum (*P) || *P == '_') {
220         ++P;
221     }
222
223     /* Do we have a value given? */
224     if (*P != '=') {
225         if (*P != '\0') {
226             InvDef (Def);
227         }
228         /* No value given. Define the macro with the value 1 */
229         AddNumericMacro (Def, 1);
230     } else {
231         /* We have a value, P points to the '=' character. Since the argument
232          * is const, create a copy and replace the '=' in the copy by a zero
233          * terminator.
234          */
235         char* Q;
236         unsigned Len = strlen (Def)+1;
237         char* S = xmalloc (Len);
238         memcpy (S, Def, Len);
239         Q = S + (P - Def);
240         *Q++ = '\0';
241
242         /* Define this as a macro */
243         AddTextMacro (S, Q);
244
245         /* Release the allocated memory */
246         xfree (S);
247     }
248 }
249
250
251
252 static void CheckSegName (const char* Seg)
253 /* Abort if the given name is not a valid segment name */
254 {
255     /* Print an error and abort if the name is not ok */
256     if (!ValidSegName (Seg)) {
257         AbEnd ("Segment name `%s' is invalid", Seg);
258     }
259 }
260
261
262
263 static void OptAddSource (const char* Opt, const char* Arg)
264 /* Add source lines as comments in generated assembler file */
265 {
266     AddSource = 1;
267 }
268
269
270
271 static void OptAnsi (const char* Opt, const char* Arg)
272 /* Compile in strict ANSI mode */
273 {
274     ANSI = 1;
275 }
276
277
278
279 static void OptBssName (const char* Opt, const char* Arg)
280 /* Handle the --bss-name option */
281 {
282     /* Check for a valid name */
283     CheckSegName (Arg);
284
285     /* Set the name */
286     NewSegName (SEG_BSS, Arg);
287 }
288
289
290
291 static void OptCodeName (const char* Opt, const char* Arg)
292 /* Handle the --code-name option */
293 {
294     /* Check for a valid name */
295     CheckSegName (Arg);
296
297     /* Set the name */
298     NewSegName (SEG_CODE, Arg);
299 }
300
301
302
303 static void OptCreateDep (const char* Opt, const char* Arg)
304 /* Handle the --create-dep option */
305 {
306     CreateDep = 1;
307 }
308
309
310
311 static void OptCPU (const char* Opt, const char* Arg)
312 /* Handle the --cpu option */
313 {
314     if (strcmp (Arg, "6502") == 0) {
315         CPU = CPU_6502;
316     } else if (strcmp (Arg, "65C02") == 0) {
317         CPU = CPU_65C02;
318     } else {
319         AbEnd ("Invalid CPU: `%s'", Arg);
320     }
321 }
322
323
324
325 static void OptDataName (const char* Opt, const char* Arg)
326 /* Handle the --code-name option */
327 {
328     /* Check for a valid name */
329     CheckSegName (Arg);
330
331     /* Set the name */
332     NewSegName (SEG_DATA, Arg);
333 }
334
335
336
337 static void OptDebug (const char* Opt, const char* Arg)
338 /* Compiler debug mode */
339 {
340     Debug = 1;
341 }
342
343
344
345 static void OptDebugInfo (const char* Opt, const char* Arg)
346 /* Add debug info to the object file */
347 {
348     DebugInfo = 1;
349 }
350
351
352
353 static void OptHelp (const char* Opt, const char* Arg)
354 /* Print usage information and exit */
355 {
356     Usage ();
357     exit (EXIT_SUCCESS);
358 }
359
360
361
362 static void OptIncludeDir (const char* Opt, const char* Arg)
363 /* Add an include search path */
364 {
365     AddIncludePath (Arg, INC_SYS | INC_USER);
366 }
367
368
369
370 static void OptRodataName (const char* Opt, const char* Arg)
371 /* Handle the --rodata-name option */
372 {
373     /* Check for a valid name */
374     CheckSegName (Arg);
375
376     /* Set the name */
377     NewSegName (SEG_RODATA, Arg);
378 }
379
380
381
382 static void OptSignedChars (const char* Opt, const char* Arg)
383 /* Make default characters signed */
384 {
385     SignedChars = 1;
386 }
387
388
389
390 static void OptStaticLocals (const char* Opt, const char* Arg)
391 /* Place local variables in static storage */
392 {
393     StaticLocals = 1;
394 }
395
396
397
398 static void OptTarget (const char* Opt, const char* Arg)
399 /* Set the target system */
400 {
401     SetSys (Arg);
402 }
403
404
405
406 static void OptVerbose (const char* Opt, const char* Arg)
407 /* Increase verbosity */
408 {
409     ++Verbose;
410 }
411
412
413
414 static void OptVersion (const char* Opt, const char* Arg)
415 /* Print the assembler version */
416 {
417     fprintf (stderr,
418              "cc65 V%u.%u.%u\n",
419              VER_MAJOR, VER_MINOR, VER_PATCH);
420 }
421
422
423
424 int main (int argc, char* argv[])
425 {
426     /* Program long options */
427     static const LongOpt OptTab[] = {
428         { "--add-source",       0,      OptAddSource            },
429         { "--ansi",             0,      OptAnsi                 },
430         { "--bss-name",         1,      OptBssName              },
431         { "--code-name",        1,      OptCodeName             },
432         { "--create-dep",       0,      OptCreateDep            },
433         { "--cpu",              1,      OptCPU                  },
434         { "--data-name",        1,      OptDataName             },
435         { "--debug",            0,      OptDebug                },
436         { "--debug-info",       0,      OptDebugInfo            },
437         { "--help",             0,      OptHelp                 },
438         { "--include-dir",      1,      OptIncludeDir           },
439         { "--rodata-name",      1,      OptRodataName           },
440         { "--signed-chars",     0,      OptSignedChars          },
441         { "--static-locals",    0,      OptStaticLocals         },
442         { "--target",           1,      OptTarget               },
443         { "--verbose",          0,      OptVerbose              },
444         { "--version",          0,      OptVersion              },
445     };
446
447     int I;
448
449     /* Initialize the output file name */
450     const char* OutputFile = 0;
451     const char* InputFile  = 0;
452
453     /* Initialize the cmdline module */
454     InitCmdLine (argc, argv, "cc65");
455
456     /* Initialize the default segment names */
457     InitSegNames ();
458
459     /* Parse the command line */
460     I = 1;
461     while (I < argc) {
462
463         const char* P;
464
465         /* Get the argument */
466         const char* Arg = argv [I];
467
468         /* Check for an option */
469         if (Arg [0] == '-') {
470
471             switch (Arg [1]) {
472
473                 case '-':
474                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
475                     break;
476
477                 case 'd':
478                     OptDebug (Arg, 0);
479                     break;
480
481                 case 'h':
482                 case '?':
483                     OptHelp (Arg, 0);
484                     break;
485
486                 case 'g':
487                     OptDebugInfo (Arg, 0);
488                     break;
489
490                 case 'j':
491                     OptSignedChars (Arg, 0);
492                     break;
493
494                 case 'o':
495                     OutputFile = GetArg (&I, 2);
496                     break;
497
498                 case 't':
499                     OptTarget (Arg, GetArg (&I, 2));
500                     break;
501
502                 case 'u':
503                     OptCreateDep (Arg, 0);
504                     break;
505
506                 case 'v':
507                     OptVerbose (Arg, 0);
508                     break;
509
510                 case 'A':
511                     OptAnsi (Arg, 0);
512                     break;
513
514                 case 'C':
515                     P = Arg + 2;
516                     while (*P) {
517                         switch (*P++) {
518                             case 'l':
519                                 OptStaticLocals (Arg, 0);
520                                 break;
521                             default:
522                                 UnknownOption (Arg);
523                                 break;
524                         }
525                     }
526                     break;
527
528                 case 'D':
529                     DefineSym (GetArg (&I, 2));
530                     break;
531
532                 case 'I':
533                     OptIncludeDir (Arg, GetArg (&I, 2));
534                     break;
535
536                 case 'O':
537                     Optimize = 1;
538                     P = Arg + 2;
539                     while (*P) {
540                         switch (*P++) {
541                             case 'f':
542                                 sscanf (P, "%lx", (long*) &OptDisable);
543                                 break;
544                             case 'i':
545                                 FavourSize = 0;
546                                 break;
547                             case 'r':
548                                 EnableRegVars = 1;
549                                 break;
550                             case 's':
551                                 InlineStdFuncs = 1;
552                                 break;
553                         }
554                     }
555                     break;
556
557                 case 'T':
558                     OptAddSource (Arg, 0);
559                     break;
560
561                 case 'V':
562                     OptVersion (Arg, 0);
563                     break;
564
565                 case 'W':
566                     NoWarn = 1;
567                     break;
568
569                 default:
570                     UnknownOption (Arg);
571                     break;
572             }
573         } else {
574             if (InputFile) {
575                 fprintf (stderr, "additional file specs ignored\n");
576             } else {
577                 InputFile = Arg;
578             }
579         }
580
581         /* Next argument */
582         ++I;
583     }
584
585     /* Did we have a file spec on the command line? */
586     if (InputFile == 0) {
587         AbEnd ("No input files");
588     }
589
590     /* Open the input file */
591     OpenMainFile (InputFile);
592
593     /* Create the output file name if it was not explicitly given */
594     if (OutputFile == 0) {
595         OutputFile = MakeFilename (InputFile, ".s");
596     }
597
598     /* Go! */
599     Compile ();
600
601     /* Create the output file if we didn't had any errors */
602     if (ErrorCount == 0 || Debug) {
603
604         FILE* F;
605
606         /* Optimize the output if requested */
607         if (Optimize) {
608             OptDoOpt ();
609         }
610
611         /* Open the file */
612         F = fopen (OutputFile, "w");
613         if (F == 0) {
614             Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
615         }
616
617         /* Write the output to the file */
618         WriteOutput (F);
619
620         /* Close the file, check for errors */
621         if (fclose (F) != 0) {
622             remove (OutputFile);
623             Fatal (FAT_CANNOT_WRITE_OUTPUT);
624         }
625
626         /* Create dependencies if requested */
627         if (CreateDep) {
628             DoCreateDep (OutputFile);
629         }
630
631     }
632
633     /* Return an apropriate exit code */
634     return (ErrorCount > 0)? EXIT_FAILURE : EXIT_SUCCESS;
635 }
636
637
638