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