1/*****************************************************************************/
2/* */
3/* main.c */
4/* */
5/* cc65 main program */
6/* */
7/* */
8/* */
9/* (C) 2000-2015, 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 <string.h>
38#include <stdlib.h>
39#include <errno.h>
40
41/* common */
42#include "abend.h"
43#include "chartype.h"
44#include "cmdline.h"
45#include "cpu.h"
46#include "debugflag.h"
47#include "fname.h"
48#include "mmodel.h"
49#include "print.h"
50#include "segnames.h"
51#include "strbuf.h"
52#include "target.h"
53#include "tgttrans.h"
54#include "version.h"
55#include "xmalloc.h"
56
57/* cc65 */
58#include "asmcode.h"
59#include "compile.h"
60#include "codeopt.h"
61#include "error.h"
62#include "global.h"
63#include "incpath.h"
64#include "input.h"
65#include "macrotab.h"
66#include "output.h"
67#include "scanner.h"
68#include "segments.h"
69#include "standard.h"
70
71
72
73/*****************************************************************************/
74/* Code */
75/*****************************************************************************/
76
77
78
79static void Usage (void)
80/* Print usage information to stderr */
81{
82 printf ("Usage: %s [options] file\n"
83 "Short options:\n"
84 " -Cl\t\t\t\tMake local variables static\n"
85 " -Dsym[=defn]\t\t\tDefine a symbol\n"
86 " -E\t\t\t\tStop after the preprocessing stage\n"
87 " -I dir\t\t\tSet an include directory search path\n"
88 " -O\t\t\t\tOptimize code\n"
89 " -Oi\t\t\t\tOptimize code, inline more code\n"
90 " -Or\t\t\t\tEnable register variables\n"
91 " -Os\t\t\t\tInline some standard functions\n"
92 " -T\t\t\t\tInclude source as comment\n"
93 " -V\t\t\t\tPrint the compiler version number\n"
94 " -W warning[,...]\t\tSuppress warnings\n"
95 " -d\t\t\t\tDebug mode\n"
96 " -g\t\t\t\tAdd debug info to object file\n"
97 " -h\t\t\t\tHelp (this text)\n"
98 " -j\t\t\t\tDefault characters are signed\n"
99 " -mm model\t\t\tSet the memory model\n"
100 " -o name\t\t\tName the output file\n"
101 " -r\t\t\t\tEnable register variables\n"
102 " -t sys\t\t\tSet the target system\n"
103 " -v\t\t\t\tIncrease verbosity\n"
104 "\n"
105 "Long options:\n"
106 " --add-source\t\t\tInclude source as comment\n"
107 " --all-cdecl\t\t\tMake functions default to __cdecl__\n"
108 " --bss-name seg\t\tSet the name of the BSS segment\n"
109 " --check-stack\t\t\tGenerate stack overflow checks\n"
110 " --code-name seg\t\tSet the name of the CODE segment\n"
111 " --codesize x\t\t\tAccept larger code by factor x\n"
112 " --cpu type\t\t\tSet cpu type (6502, 65c02)\n"
113 " --create-dep name\t\tCreate a make dependency file\n"
114 " --create-full-dep name\tCreate a full make dependency file\n"
115 " --data-name seg\t\tSet the name of the DATA segment\n"
116 " --debug\t\t\tDebug mode\n"
117 " --debug-info\t\t\tAdd debug info to object file\n"
118 " --debug-opt name\t\tDebug optimization steps\n"
119 " --dep-target target\t\tUse this dependency target\n"
120 " --disable-opt name\t\tDisable an optimization step\n"
121 " --eagerly-inline-funcs\tEagerly inline some known functions\n"
122 " --enable-opt name\t\tEnable an optimization step\n"
123 " --help\t\t\tHelp (this text)\n"
124 " --include-dir dir\t\tSet an include directory search path\n"
125 " --inline-stdfuncs\t\tInline some standard functions\n"
126 " --list-opt-steps\t\tList all optimizer steps and exit\n"
127 " --list-warnings\t\tList available warning types for -W\n"
128 " --local-strings\t\tEmit string literals immediately\n"
129 " --memory-model model\t\tSet the memory model\n"
130 " --register-space b\t\tSet space available for register variables\n"
131 " --register-vars\t\tEnable register variables\n"
132 " --rodata-name seg\t\tSet the name of the RODATA segment\n"
133 " --signed-chars\t\tDefault characters are signed\n"
134 " --standard std\t\tLanguage standard (c89, c99, cc65)\n"
135 " --static-locals\t\tMake local variables static\n"
136 " --target sys\t\t\tSet the target system\n"
137 " --verbose\t\t\tIncrease verbosity\n"
138 " --version\t\t\tPrint the compiler version number\n"
139 " --writable-strings\t\tMake string literals writable\n",
140 ProgName);
141}
142
143
144
145static void cbmsys (const char* sys)
146/* Define a CBM system */
147{
148 DefineNumericMacro ("__CBM__", 1);
149 DefineNumericMacro (sys, 1);
150}
151
152
153
154static void SetSys (const char* Sys)
155/* Define a target system */
156{
157 switch (Target = FindTarget (Sys)) {
158
159 case TGT_NONE:
160 break;
161
162 case TGT_MODULE:
163 AbEnd ("Cannot use 'module' as a target for the compiler");
164 break;
165
166 case TGT_ATARI2600:
167 DefineNumericMacro ("__ATARI2600__", 1);
168 break;
169
170 case TGT_ATARI5200:
171 DefineNumericMacro ("__ATARI5200__", 1);
172 break;
173
174 case TGT_ATARI:
175 DefineNumericMacro ("__ATARI__", 1);
176 break;
177
178 case TGT_ATARIXL:
179 DefineNumericMacro ("__ATARI__", 1);
180 DefineNumericMacro ("__ATARIXL__", 1);
181 break;
182
183 case TGT_C16:
184 cbmsys ("__C16__");
185 break;
186
187 case TGT_C64:
188 cbmsys ("__C64__");
189 break;
190
191 case TGT_VIC20:
192 cbmsys ("__VIC20__");
193 break;
194
195 case TGT_C128:
196 cbmsys ("__C128__");
197 break;
198
199 case TGT_PLUS4:
200 cbmsys ("__C16__");
201 DefineNumericMacro ("__PLUS4__", 1);
202 break;
203
204 case TGT_CBM510:
205 cbmsys ("__CBM510__");
206 break;
207
208 case TGT_CBM610:
209 cbmsys ("__CBM610__");
210 break;
211
212 case TGT_PET:
213 cbmsys ("__PET__");
214 break;
215
216 case TGT_BBC:
217 DefineNumericMacro ("__BBC__", 1);
218 break;
219
220 case TGT_APPLE2:
221 DefineNumericMacro ("__APPLE2__", 1);
222 break;
223
224 case TGT_APPLE2ENH:
225 DefineNumericMacro ("__APPLE2__", 1);
226 DefineNumericMacro ("__APPLE2ENH__", 1);
227 break;
228
229 case TGT_GAMATE:
230 DefineNumericMacro ("__GAMATE__", 1);
231 break;
232
233 case TGT_GEOS_CBM:
234 /* Do not handle as a CBM system */
235 DefineNumericMacro ("__GEOS__", 1);
236 DefineNumericMacro ("__GEOS_CBM__", 1);
237 break;
238
239 case TGT_CREATIVISION:
240 DefineNumericMacro ("__CREATIVISION__", 1);
241 break;
242
243 case TGT_GEOS_APPLE:
244 DefineNumericMacro ("__GEOS__", 1);
245 DefineNumericMacro ("__GEOS_APPLE__", 1);
246 break;
247
248 case TGT_LUNIX:
249 DefineNumericMacro ("__LUNIX__", 1);
250 break;
251
252 case TGT_ATMOS:
253 DefineNumericMacro ("__ATMOS__", 1);
254 break;
255
256 case TGT_TELESTRAT:
257 DefineNumericMacro ("__TELESTRAT__", 1);
258 break;
259
260 case TGT_NES:
261 DefineNumericMacro ("__NES__", 1);
262 break;
263
264 case TGT_SUPERVISION:
265 DefineNumericMacro ("__SUPERVISION__", 1);
266 break;
267
268 case TGT_LYNX:
269 DefineNumericMacro ("__LYNX__", 1);
270 break;
271
272 case TGT_SIM6502:
273 DefineNumericMacro ("__SIM6502__", 1);
274 break;
275
276 case TGT_SIM65C02:
277 DefineNumericMacro ("__SIM65C02__", 1);
278 break;
279
280 case TGT_OSIC1P:
281 DefineNumericMacro ("__OSIC1P__", 1);
282 break;
283
284 case TGT_PCENGINE:
285 DefineNumericMacro ("__PCE__", 1);
286 break;
287
288 default:
289 AbEnd ("Unknown target system type %d", Target);
290 }
291
292 /* Initialize the translation tables for the target system */
293 TgtTranslateInit ();
294}
295
296
297
298static void FileNameOption (const char* Opt, const char* Arg, StrBuf* Name)
299/* Handle an option that remembers a file name for later */
300{
301 /* Cannot have the option twice */
302 if (SB_NotEmpty (Name)) {
303 AbEnd ("Cannot use option '%s' twice", Opt);
304 }
305 /* A typo in OptTab[] might allow a NULL Arg */
306 if (Arg == 0) {
307 Internal ("Typo in OptTab[]; option '%s' should require an argument", Opt);
308 }
309 /* Remember the file name for later */
310 SB_CopyStr (Name, Arg);
311 SB_Terminate (Name);
312}
313
314
315
316static void DefineSym (const char* Def)
317/* Define a symbol on the command line */
318{
319 const char* P = Def;
320
321 /* The symbol must start with a character or underline */
322 if (Def [0] != '_' && !IsAlpha (Def [0])) {
323 InvDef (Def);
324 }
325
326 /* Check the symbol name */
327 while (IsAlNum (*P) || *P == '_') {
328 ++P;
329 }
330
331 /* Do we have a value given? */
332 if (*P != '=') {
333 if (*P != '\0') {
334 InvDef (Def);
335 }
336 /* No value given. Define the macro with the value 1 */
337 DefineNumericMacro (Def, 1);
338 } else {
339 /* We have a value, P points to the '=' character. Since the argument
340 ** is const, create a copy and replace the '=' in the copy by a zero
341 ** terminator.
342 */
343 char* Q;
344 unsigned Len = strlen (Def)+1;
345 char* S = (char*) xmalloc (Len);
346 memcpy (S, Def, Len);
347 Q = S + (P - Def);
348 *Q++ = '\0';
349
350 /* Define this as a macro */
351 DefineTextMacro (S, Q);
352
353 /* Release the allocated memory */
354 xfree (S);
355 }
356}
357
358
359
360static void CheckSegName (const char* Seg)
361/* Abort if the given name is not a valid segment name */
362{
363 /* Print an error and abort if the name is not ok */
364 if (!ValidSegName (Seg)) {
365 AbEnd ("Segment name '%s' is invalid", Seg);
366 }
367}
368
369
370
371static void OptAddSource (const char* Opt attribute ((unused)),
372 const char* Arg attribute ((unused)))
373/* Add source lines as comments in generated assembler file */
374{
375 AddSource = 1;
376}
377
378
379
380static void OptAllCDecl (const char* Opt attribute ((unused)),
381 const char* Arg attribute ((unused)))
382/* Make functions default to cdecl instead of fastcall. */
383{
384 AutoCDecl = 1;
385}
386
387
388
389static void OptBssName (const char* Opt attribute ((unused)), const char* Arg)
390/* Handle the --bss-name option */
391{
392 /* Check for a valid name */
393 CheckSegName (Arg);
394
395 /* Set the name */
396 SetSegName (SEG_BSS, Arg);
397}
398
399
400
401static void OptCheckStack (const char* Opt attribute ((unused)),
402 const char* Arg attribute ((unused)))
403/* Handle the --check-stack option */
404{
405 IS_Set (&CheckStack, 1);
406}
407
408
409
410static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg)
411/* Handle the --code-name option */
412{
413 /* Check for a valid name */
414 CheckSegName (Arg);
415
416 /* Set the name */
417 SetSegName (SEG_CODE, Arg);
418}
419
420
421
422static void OptCodeSize (const char* Opt, const char* Arg)
423/* Handle the --codesize option */
424{
425 unsigned Factor;
426 char BoundsCheck;
427
428 /* Numeric argument expected */
429 if (sscanf (Arg, "%u%c", &Factor, &BoundsCheck) != 1 ||
430 Factor < 10 || Factor > 1000) {
431 AbEnd ("Argument for %s is invalid", Opt);
432 }
433 IS_Set (&CodeSizeFactor, Factor);
434}
435
436
437
438static void OptCreateDep (const char* Opt, const char* Arg)
439/* Handle the --create-dep option */
440{
441 FileNameOption (Opt, Arg, &DepName);
442}
443
444
445
446static void OptCreateFullDep (const char* Opt attribute ((unused)),
447 const char* Arg)
448/* Handle the --create-full-dep option */
449{
450 FileNameOption (Opt, Arg, &FullDepName);
451}
452
453
454
455static void OptCPU (const char* Opt, const char* Arg)
456/* Handle the --cpu option */
457{
458 /* Find the CPU from the given name */
459 CPU = FindCPU (Arg);
460 if (CPU != CPU_6502 && CPU != CPU_6502X && CPU != CPU_65SC02 &&
461 CPU != CPU_65C02 && CPU != CPU_65816 && CPU != CPU_HUC6280) {
462 AbEnd ("Invalid argument for %s: '%s'", Opt, Arg);
463 }
464}
465
466
467
468static void OptDataName (const char* Opt attribute ((unused)), const char* Arg)
469/* Handle the --data-name option */
470{
471 /* Check for a valid name */
472 CheckSegName (Arg);
473
474 /* Set the name */
475 SetSegName (SEG_DATA, Arg);
476}
477
478
479
480static void OptDebug (const char* Opt attribute ((unused)),
481 const char* Arg attribute ((unused)))
482/* Compiler debug mode */
483{
484 ++Debug;
485}
486
487
488
489static void OptDebugInfo (const char* Opt attribute ((unused)),
490 const char* Arg attribute ((unused)))
491/* Add debug info to the object file */
492{
493 DebugInfo = 1;
494}
495
496
497
498static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg)
499/* Debug optimization steps */
500{
501 char Buf [128];
502 char* Line;
503
504 /* Open the file */
505 FILE* F = fopen (Arg, "r");
506 if (F == 0) {
507 AbEnd ("Cannot open '%s': %s", Arg, strerror (errno));
508 }
509
510 /* Read line by line, ignore empty lines and switch optimization
511 ** steps on/off.
512 */
513 while (fgets (Buf, sizeof (Buf), F) != 0) {
514
515 /* Remove trailing control chars. This will also remove the
516 ** trailing newline.
517 */
518 unsigned Len = strlen (Buf);
519 while (Len > 0 && IsControl (Buf[Len-1])) {
520 --Len;
521 }
522 Buf[Len] = '\0';
523
524 /* Get a pointer to the buffer and remove leading white space */
525 Line = Buf;
526 while (IsBlank (*Line)) {
527 ++Line;
528 }
529
530 /* Check the first character and enable/disable the step or
531 ** ignore the line
532 */
533 switch (*Line) {
534
535 case '\0':
536 case '#':
537 case ';':
538 /* Empty or comment line */
539 continue;
540
541 case '-':
542 DisableOpt (Line+1);
543 break;
544
545 case '+':
546 ++Line;
547 /* FALLTHROUGH */
548
549 default:
550 EnableOpt (Line);
551 break;
552
553 }
554
555 }
556
557 /* Close the file, no error check here since we were just reading and
558 ** this is only a debug function.
559 */
560 (void) fclose (F);
561}
562
563
564
565static void OptDebugOptOutput (const char* Opt attribute ((unused)),
566 const char* Arg attribute ((unused)))
567/* Output optimization steps */
568{
569 DebugOptOutput = 1;
570}
571
572
573
574static void OptDepTarget (const char* Opt attribute ((unused)), const char* Arg)
575/* Handle the --dep-target option */
576{
577 FileNameOption (Opt, Arg, &DepTarget);
578}
579
580
581
582static void OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg)
583/* Disable an optimization step */
584{
585 DisableOpt (Arg);
586}
587
588
589
590static void OptEagerlyInlineFuncs (const char* Opt attribute((unused)),
591 const char* Arg attribute((unused)))
592/* Eagerly inline some known functions */
593{
594 IS_Set (&InlineStdFuncs, 1);
595 IS_Set (&EagerlyInlineFuncs, 1);
596}
597
598
599
600static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg)
601/* Enable an optimization step */
602{
603 EnableOpt (Arg);
604}
605
606
607
608static void OptHelp (const char* Opt attribute ((unused)),
609 const char* Arg attribute ((unused)))
610/* Print usage information and exit */
611{
612 Usage ();
613 exit (EXIT_SUCCESS);
614}
615
616
617
618static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg)
619/* Add an include search path */
620{
621 AddSearchPath (SysIncSearchPath, Arg);
622 AddSearchPath (UsrIncSearchPath, Arg);
623}
624
625
626
627static void OptInlineStdFuncs (const char* Opt attribute((unused)),
628 const char* Arg attribute((unused)))
629/* Inline some standard functions */
630{
631 IS_Set (&InlineStdFuncs, 1);
632}
633
634
635
636static void OptListOptSteps (const char* Opt attribute ((unused)),
637 const char* Arg attribute ((unused)))
638/* List all optimizer steps */
639{
640 /* List the optimizer steps */
641 ListOptSteps (stdout);
642
643 /* Terminate */
644 exit (EXIT_SUCCESS);
645}
646
647
648
649static void OptListWarnings (const char* Opt attribute ((unused)),
650 const char* Arg attribute ((unused)))
651/* List all warning types */
652{
653 /* List the warnings */
654 ListWarnings (stdout);
655
656 /* Terminate */
657 exit (EXIT_SUCCESS);
658}
659
660
661
662static void OptLocalStrings (const char* Opt attribute ((unused)),
663 const char* Arg attribute ((unused)))
664/* Emit string literals immediately */
665{
666 IS_Set (&LocalStrings, 1);
667}
668
669
670
671static void OptMemoryModel (const char* Opt, const char* Arg)
672/* Set the memory model */
673{
674 mmodel_t M;
675
676 /* Check the current memory model */
677 if (MemoryModel != MMODEL_UNKNOWN) {
678 AbEnd ("Cannot use option '%s' twice", Opt);
679 }
680
681 /* Translate the memory model name and check it */
682 M = FindMemoryModel (Arg);
683 if (M == MMODEL_UNKNOWN) {
684 AbEnd ("Unknown memory model: %s", Arg);
685 } else if (M == MMODEL_HUGE) {
686 AbEnd ("Unsupported memory model: %s", Arg);
687 }
688
689 /* Set the memory model */
690 SetMemoryModel (M);
691}
692
693
694
695static void OptRegisterSpace (const char* Opt, const char* Arg)
696/* Handle the --register-space option */
697{
698 /* Numeric argument expected */
699 if (sscanf (Arg, "%u", &RegisterSpace) != 1 || RegisterSpace > 256) {
700 AbEnd ("Argument for option %s is invalid", Opt);
701 }
702}
703
704
705
706static void OptRegisterVars (const char* Opt attribute ((unused)),
707 const char* Arg attribute ((unused)))
708/* Handle the --register-vars option */
709{
710 IS_Set (&EnableRegVars, 1);
711}
712
713
714
715static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
716/* Handle the --rodata-name option */
717{
718 /* Check for a valid name */
719 CheckSegName (Arg);
720
721 /* Set the name */
722 SetSegName (SEG_RODATA, Arg);
723}
724
725
726
727static void OptSignedChars (const char* Opt attribute ((unused)),
728 const char* Arg attribute ((unused)))
729/* Make default characters signed */
730{
731 IS_Set (&SignedChars, 1);
732}
733
734
735
736static void OptStandard (const char* Opt, const char* Arg)
737/* Handle the --standard option */
738{
739 /* Find the standard from the given name */
740 standard_t Std = FindStandard (Arg);
741 if (Std == STD_UNKNOWN) {
742 AbEnd ("Invalid argument for %s: '%s'", Opt, Arg);
743 } else if (IS_Get (&Standard) != STD_UNKNOWN) {
744 AbEnd ("Option %s given more than once", Opt);
745 } else {
746 IS_Set (&Standard, Std);
747 }
748}
749
750
751
752static void OptStaticLocals (const char* Opt attribute ((unused)),
753 const char* Arg attribute ((unused)))
754/* Place local variables in static storage */
755{
756 IS_Set (&StaticLocals, 1);
757}
758
759
760
761static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
762/* Set the target system */
763{
764 SetSys (Arg);
765}
766
767
768
769static void OptVerbose (const char* Opt attribute ((unused)),
770 const char* Arg attribute ((unused)))
771/* Increase verbosity */
772{
773 ++Verbosity;
774}
775
776
777
778static void OptVersion (const char* Opt attribute ((unused)),
779 const char* Arg attribute ((unused)))
780/* Print the compiler version */
781{
782 fprintf (stderr, "%s V%s\n", ProgName, GetVersionAsString ());
783 exit (EXIT_SUCCESS);
784}
785
786
787
788static void OptWarning (const char* Opt attribute ((unused)), const char* Arg)
789/* Handle the -W option */
790{
791 StrBuf W = AUTO_STRBUF_INITIALIZER;
792
793 /* Arg is a list of suboptions, separated by commas */
794 while (Arg) {
795
796 const char* Pos;
797 int Enabled = 1;
798 IntStack* S;
799
800 /* The suboption may be prefixed with '-' or '+' */
801 if (*Arg == '-') {
802 Enabled = 0;
803 ++Arg;
804 } else if (*Arg == '+') {
805 /* This is the default */
806 ++Arg;
807 }
808
809 /* Get the next suboption */
810 Pos = strchr (Arg, ',');
811 if (Pos) {
812 SB_CopyBuf (&W, Arg, Pos - Arg);
813 Arg = Pos + 1;
814 } else {
815 SB_CopyStr (&W, Arg);
816 Arg = 0;
817 }
818 SB_Terminate (&W);
819
820 /* Search for the warning */
821 S = FindWarning (SB_GetConstBuf (&W));
822 if (S == 0) {
823 InvArg (Opt, SB_GetConstBuf (&W));
824 }
825 IS_Set (S, Enabled);
826 }
827
828 /* Free allocated memory */
829 SB_Done (&W);
830}
831
832
833
834static void OptWritableStrings (const char* Opt attribute ((unused)),
835 const char* Arg attribute ((unused)))
836/* Make string literals writable */
837{
838 IS_Set (&WritableStrings, 1);
839}
840
841
842
843int main (int argc, char* argv[])
844{
845 /* Program long options */
846 static const LongOpt OptTab[] = {
847 { "--add-source", 0, OptAddSource },
848 { "--all-cdecl", 0, OptAllCDecl },
849 { "--bss-name", 1, OptBssName },
850 { "--check-stack", 0, OptCheckStack },
851 { "--code-name", 1, OptCodeName },
852 { "--codesize", 1, OptCodeSize },
853 { "--cpu", 1, OptCPU },
854 { "--create-dep", 1, OptCreateDep },
855 { "--create-full-dep", 1, OptCreateFullDep },
856 { "--data-name", 1, OptDataName },
857 { "--debug", 0, OptDebug },
858 { "--debug-info", 0, OptDebugInfo },
859 { "--debug-opt", 1, OptDebugOpt },
860 { "--debug-opt-output", 0, OptDebugOptOutput },
861 { "--dep-target", 1, OptDepTarget },
862 { "--disable-opt", 1, OptDisableOpt },
863 { "--eagerly-inline-funcs", 0, OptEagerlyInlineFuncs },
864 { "--enable-opt", 1, OptEnableOpt },
865 { "--help", 0, OptHelp },
866 { "--include-dir", 1, OptIncludeDir },
867 { "--inline-stdfuncs", 0, OptInlineStdFuncs },
868 { "--list-opt-steps", 0, OptListOptSteps },
869 { "--list-warnings", 0, OptListWarnings },
870 { "--local-strings", 0, OptLocalStrings },
871 { "--memory-model", 1, OptMemoryModel },
872 { "--register-space", 1, OptRegisterSpace },
873 { "--register-vars", 0, OptRegisterVars },
874 { "--rodata-name", 1, OptRodataName },
875 { "--signed-chars", 0, OptSignedChars },
876 { "--standard", 1, OptStandard },
877 { "--static-locals", 0, OptStaticLocals },
878 { "--target", 1, OptTarget },
879 { "--verbose", 0, OptVerbose },
880 { "--version", 0, OptVersion },
881 { "--writable-strings", 0, OptWritableStrings },
882 };
883
884 unsigned I;
885
886 /* Initialize the input file name */
887 const char* InputFile = 0;
888
889 /* Initialize the cmdline module */
890 InitCmdLine (&argc, &argv, "cc65");
891
892 /* Initialize the default segment names */
893 InitSegNames ();
894
895 /* Initialize the include search paths */
896 InitIncludePaths ();
897
898 /* Parse the command line */
899 I = 1;
900 while (I < ArgCount) {
901
902 const char* P;
903
904 /* Get the argument */
905 const char* Arg = ArgVec[I];
906
907 /* Check for an option */
908 if (Arg[0] == '-') {
909
910 switch (Arg[1]) {
911
912 case '-':
913 LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
914 break;
915
916 case 'd':
917 OptDebug (Arg, 0);
918 break;
919
920 case 'h':
921 case '?':
922 OptHelp (Arg, 0);
923 break;
924
925 case 'g':
926 OptDebugInfo (Arg, 0);
927 break;
928
929 case 'j':
930 OptSignedChars (Arg, 0);
931 break;
932
933 case 'o':
934 SetOutputName (GetArg (&I, 2));
935 break;
936
937 case 'r':
938 OptRegisterVars (Arg, 0);
939 break;
940
941 case 't':
942 OptTarget (Arg, GetArg (&I, 2));
943 break;
944
945 case 'u':
946 OptCreateDep (Arg, 0);
947 break;
948
949 case 'v':
950 OptVerbose (Arg, 0);
951 break;
952
953 case 'C':
954 P = Arg + 2;
955 while (*P) {
956 switch (*P++) {
957 case 'l':
958 OptStaticLocals (Arg, 0);
959 break;
960 default:
961 UnknownOption (Arg);
962 break;
963 }
964 }
965 break;
966
967 case 'D':
968 DefineSym (GetArg (&I, 2));
969 break;
970
971 case 'E':
972 PreprocessOnly = 1;
973 break;
974
975 case 'I':
976 OptIncludeDir (Arg, GetArg (&I, 2));
977 break;
978
979 case 'O':
980 IS_Set (&Optimize, 1);
981 P = Arg + 2;
982 while (*P) {
983 switch (*P++) {
984 case 'i':
985 IS_Set (&CodeSizeFactor, 200);
986 break;
987 case 'r':
988 IS_Set (&EnableRegVars, 1);
989 break;
990 case 's':
991 IS_Set (&InlineStdFuncs, 1);
992 break;
993 default:
994 UnknownOption (Arg);
995 break;
996 }
997 }
998 break;
999
1000 case 'T':
1001 OptAddSource (Arg, 0);
1002 break;
1003
1004 case 'V':
1005 OptVersion (Arg, 0);
1006 break;
1007
1008 case 'W':
1009 OptWarning (Arg, GetArg (&I, 2));
1010 break;
1011
1012 default:
1013 UnknownOption (Arg);
1014 break;
1015 }
1016 } else {
1017 if (InputFile) {
1018 fprintf (stderr, "additional file specs ignored\n");
1019 } else {
1020 InputFile = Arg;
1021 }
1022 }
1023
1024 /* Next argument */
1025 ++I;
1026 }
1027
1028 /* Did we have a file spec on the command line? */
1029 if (InputFile == 0) {
1030 AbEnd ("No input files");
1031 }
1032
1033 /* Add the default include search paths. */
1034 FinishIncludePaths ();
1035
1036 /* Create the output file name if it was not explicitly given */
1037 MakeDefaultOutputName (InputFile);
1038
1039 /* If no CPU given, use the default CPU for the target */
1040 if (CPU == CPU_UNKNOWN) {
1041 if (Target != TGT_UNKNOWN) {
1042 CPU = GetTargetProperties (Target)->DefaultCPU;
1043 } else {
1044 CPU = CPU_6502;
1045 }
1046 }
1047
1048 /* If no memory model was given, use the default */
1049 if (MemoryModel == MMODEL_UNKNOWN) {
1050 SetMemoryModel (MMODEL_NEAR);
1051 }
1052
1053 /* If no language standard was given, use the default one */
1054 if (IS_Get (&Standard) == STD_UNKNOWN) {
1055 IS_Set (&Standard, STD_DEFAULT);
1056 }
1057
1058 /* Go! */
1059 Compile (InputFile);
1060
1061 /* Create the output file if we didn't had any errors */
1062 if (PreprocessOnly == 0 && (ErrorCount == 0 || Debug)) {
1063
1064 /* Emit literals, externals, do cleanup and optimizations */
1065 FinishCompile ();
1066
1067 /* Open the file */
1068 OpenOutputFile ();
1069
1070 /* Write the output to the file */
1071 WriteAsmOutput ();
1072 Print (stdout, 1, "Wrote output to '%s'\n", OutputFilename);
1073
1074 /* Close the file, check for errors */
1075 CloseOutputFile ();
1076
1077 /* Create dependencies if requested */
1078 CreateDependencies ();
1079 }
1080
1081 /* Return an apropriate exit code */
1082 return (ErrorCount > 0)? EXIT_FAILURE : EXIT_SUCCESS;
1083}
1084