]> git.sur5r.net Git - cc65/blob - src/cc65/main.c
Added support for old style (K&R) function declarations.
[cc65] / src / cc65 / main.c
1 /* CC65 main program */
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <ctype.h>
7 #include <errno.h>
8
9 #include "../common/version.h"
10
11 #include "asmcode.h"
12 #include "compile.h"
13 #include "error.h"
14 #include "global.h"
15 #include "include.h"
16 #include "io.h"
17 #include "macrotab.h"
18 #include "mem.h"
19 #include "optimize.h"
20 #include "scanner.h"
21
22
23
24 /*****************************************************************************/
25 /*                                   data                                    */
26 /*****************************************************************************/
27
28
29
30 /* Names of the target systems sorted by target name */
31 static const char* TargetNames [] = {
32     "none",
33     "atari",
34     "c64",
35     "c128",
36     "ace",
37     "plus4",
38     "cbm610",
39     "pet",
40     "nes",
41     "apple2",
42     "geos",
43 };
44
45
46
47 /*****************************************************************************/
48 /*                                   Code                                    */
49 /*****************************************************************************/
50
51
52
53 static void usage (int ExitCode)
54 {
55     fputs ("Usage: cc65 [options] file\n"
56            "\t-d\t\tDebug mode\n"
57            "\t-g\t\tAdd debug info to object files\n"
58            "\t-h\t\tPrint this help\n"
59            "\t-j\t\tDefault characters are signed\n"
60            "\t-o name\t\tName the output file\n"
61            "\t-tx\t\tSet target system x\n"
62            "\t-v\t\tVerbose mode\n"
63            "\t-A\t\tStrict ANSI mode\n"
64            "\t-Cl\t\tMake local variables static\n"
65            "\t-Dsym[=defn]\tDefine a symbol\n"
66            "\t-I path\t\tSet include directory\n"
67            "\t-O\t\tOptimize code\n"
68            "\t-Oi\t\tOptimize code, inline more code\n"
69            "\t-Or\t\tEnable register variables\n"
70            "\t-Os\t\tInline some known functions\n"
71            "\t-T\t\tInclude source as comment\n"
72            "\t-V\t\tPrint version number\n"
73            "\t-W\t\tSuppress warnings\n",
74            stderr);
75     exit (ExitCode);
76 }
77
78
79
80 static char* GetArg (int* ArgNum, char* argv [], unsigned Len)
81 /* Get an option argument */
82 {
83     char* Arg = argv [*ArgNum];
84     if (Arg [Len] != '\0') {
85         /* Argument appended */
86         return Arg + Len;
87     } else {
88         /* Separate argument */
89         Arg = argv [*ArgNum + 1];
90         if (Arg == 0) {
91             /* End of arguments */
92             fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
93             exit (EXIT_FAILURE);
94         }
95         ++(*ArgNum);
96         return Arg;
97     }
98 }
99
100
101
102 /* Define a CBM system */
103 static void cbmsys (const char* sys)
104 {
105     AddNumericMacro ("__CBM__", 1);
106     AddNumericMacro (sys, 1);
107 }
108
109
110
111 static int MapSys (const char* Name)
112 /* Map a target name to a system code. Return -1 in case of an error */
113 {
114     unsigned I;
115
116     /* Check for a numeric target */
117     if (isdigit (*Name)) {
118         int Target = atoi (Name);
119         if (Target >= 0 && Target < TGT_COUNT) {
120             return Target;
121         }
122     }
123
124     /* Check for a target string */
125     for (I = 0; I < TGT_COUNT; ++I) {
126         if (strcmp (TargetNames [I], Name) == 0) {
127             return I;
128         }
129     }
130     /* Not found */
131     return -1;
132 }
133
134
135
136 /* Define a target system */
137 static void SetSys (const char* Sys)
138 {
139     switch (Target = MapSys (Sys)) {
140
141         case TGT_NONE:
142             break;
143
144         case TGT_ATARI:
145             AddNumericMacro ("__ATARI__", 1);
146             break;
147
148         case TGT_C64:
149             cbmsys ("__C64__");
150             break;
151
152         case TGT_C128:
153             cbmsys ("__C128__");
154             break;
155
156         case TGT_ACE:
157             cbmsys ("__ACE__");
158             break;
159
160         case TGT_PLUS4:
161             cbmsys ("__PLUS4__");
162             break;
163
164         case TGT_CBM610:
165             cbmsys ("__CBM610__");
166             break;
167
168         case TGT_PET:
169             cbmsys ("__PET__");
170             break;
171
172         case TGT_NES:
173             AddNumericMacro ("__NES__", 1);
174             break;
175
176         case TGT_APPLE2:
177             AddNumericMacro ("__APPLE2__", 1);
178             break;
179
180         case TGT_GEOS:
181             /* Do not handle as a CBM system */
182             AddNumericMacro ("__GEOS__", 1);
183             break;
184
185         default:
186             fputs ("Unknown system type\n", stderr);
187             usage (EXIT_FAILURE);
188     }
189 }
190
191
192
193 static void InvSym (const char* Def)
194 /* Print an error about an invalid macro definition and die */
195 {
196     fprintf (stderr, "Invalid macro definition: `%s'\n", Def);
197     exit (EXIT_FAILURE);
198 }
199
200
201
202 static void DefineSym (const char* Def)
203 /* Define a symbol on the command line */
204 {
205     const char* P = Def;
206
207     /* The symbol must start with a character or underline */
208     if (Def [0] != '_' && !isalpha (Def [0])) {
209         InvSym (Def);
210     }
211
212     /* Check the symbol name */
213     while (isalnum (*P) || *P == '_') {
214         ++P;
215     }
216
217     /* Do we have a value given? */
218     if (*P != '=') {
219         if (*P != '\0') {
220             InvSym (Def);
221         }
222         /* No value given. Define the macro with the value 1 */
223         AddNumericMacro (Def, 1);
224     } else {
225         /* We have a value, P points to the '=' character. Since the argument
226          * is const, create a copy and replace the '=' in the copy by a zero
227          * terminator.
228          */
229         char* Q;
230         unsigned Len = strlen (Def)+1;
231         char* S = xmalloc (Len);
232         memcpy (S, Def, Len);
233         Q = S + (P - Def);
234         *Q++ = '\0';
235
236         /* Define this as a macro */
237         AddTextMacro (S, Q);
238
239         /* Release the allocated memory */
240         xfree (S);
241     }
242 }
243
244
245
246 int main (int argc, char **argv)
247 {
248     int i;
249     char *argp;
250     char out_name [256];
251     char* p;
252
253     /* Initialize the output file name */
254     out_name [0] = '\0';
255
256     fin = NULL;
257
258     /* Parse the command line */
259     for (i = 1; i < argc; i++) {
260         if (*(argp = argv[i]) == '-') {
261             switch (argp[1]) {
262
263                 case 'd':       /* debug mode */
264                     Debug = 1;
265                     break;
266
267                 case 'h':
268                 case '?':
269                     usage (EXIT_SUCCESS);
270                     break;
271
272                 case 'g':
273                     DebugInfo = 1;
274                     break;
275
276                 case 'j':
277                     SignedChars = 1;
278                     break;
279
280                 case 'o':
281                     strcpy (out_name, GetArg (&i, argv, 2));
282                     break;
283
284                 case 't':
285                     SetSys (GetArg (&i, argv, 2));
286                     break;
287
288                 case 'v':
289                     ++Verbose;
290                     break;
291
292                 case 'A':
293                     ANSI = 1;
294                     break;
295
296                 case 'C':
297                     p = argp + 2;
298                     while (*p) {
299                         switch (*p++) {
300                             case 'l':
301                                 LocalsAreStatic = 1;
302                                 break;
303                         }
304                     }
305                     break;
306
307                 case 'D':
308                     DefineSym (GetArg (&i, argv, 2));
309                     break;
310
311                 case 'I':
312                     AddIncludePath (GetArg (&i, argv, 2), INC_SYS | INC_USER);
313                     break;
314
315                 case 'O':
316                     Optimize = 1;
317                     p = argp + 2;
318                     while (*p) {
319                         switch (*p++) {
320                             case 'f':
321                                 sscanf (p, "%lx", (long*) &OptDisable);
322                                 break;
323                             case 'i':
324                                 FavourSize = 0;
325                                 break;
326                             case 'r':
327                                 EnableRegVars = 1;
328                                 break;
329                             case 's':
330                                 InlineStdFuncs = 1;
331                                 break;
332                         }
333                     }
334                     break;
335
336                 case 'T':
337                     IncSource = 1;
338                     break;
339
340                 case 'V':
341                     fprintf (stderr, "cc65 V%u.%u.%u\n",
342                              VER_MAJOR, VER_MINOR, VER_PATCH);
343                     break;
344
345                 case 'W':
346                     NoWarn = 1;
347                     break;
348
349                 default:
350                     fprintf (stderr, "Invalid option %s\n", argp);
351                     usage (EXIT_FAILURE);
352             }
353         } else {
354             if (fin) {
355                 fprintf (stderr, "additional file specs ignored\n");
356             } else {
357                 fin = xstrdup (argp);
358                 inp = fopen (fin, "r");
359                 if (inp == 0) {
360                     Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno));
361                 }
362             }
363         }
364     }
365     if (!fin) {
366         fprintf (stderr, "%s: No input files\n", argv [0]);
367         exit (EXIT_FAILURE);
368     }
369
370     /* Create the output file name. We should really have
371      * some checks for string overflow, but I'll drop this because of the
372      * additional code size it would need (as in other places). Sigh.
373      */
374     if (out_name [0] == '\0') {
375         /* No output name given, create default */
376         strcpy (out_name, fin);
377         if ((p = strrchr (out_name, '.'))) {
378             *p = '\0';
379         }
380         strcat (out_name, ".s");
381     }
382
383     /* Go! */
384     Compile ();
385
386     /* Create the output file if we didn't had any errors */
387     if (ErrorCount == 0 || Debug) {
388
389         FILE* F;
390
391         /* Optimize the output if requested */
392         if (Optimize) {
393             OptDoOpt ();
394         }
395
396         /* Open the file */
397         F = fopen (out_name, "w");
398         if (F == 0) {
399             Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
400         }
401
402         /* Write the output to the file */
403         WriteOutput (F);
404
405         /* Close the file, check for errors */
406         if (fclose (F) != 0) {
407             remove (out_name);
408             Fatal (FAT_CANNOT_WRITE_OUTPUT);
409         }
410     }
411
412     /* Return an apropriate exit code */
413     return (ErrorCount > 0)? EXIT_FAILURE : EXIT_SUCCESS;
414 }
415
416