1/*****************************************************************************/
2/* */
3/* compile.c */
4/* */
5/* Top level compiler subroutine */
6/* */
7/* */
8/* */
9/* (C) 2000-2013, 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 <stdlib.h>
37#include <time.h>
38
39/* common */
40#include "debugflag.h"
41#include "segnames.h"
42#include "version.h"
43#include "xmalloc.h"
44#include "xsprintf.h"
45
46/* cc65 */
47#include "asmlabel.h"
48#include "asmstmt.h"
49#include "codegen.h"
50#include "codeopt.h"
51#include "compile.h"
52#include "declare.h"
53#include "error.h"
54#include "expr.h"
55#include "function.h"
56#include "global.h"
57#include "input.h"
58#include "litpool.h"
59#include "macrotab.h"
60#include "output.h"
61#include "pragma.h"
62#include "preproc.h"
63#include "standard.h"
64#include "symtab.h"
65
66
67
68/*****************************************************************************/
69/* Code */
70/*****************************************************************************/
71
72
73
74static void Parse (void)
75/* Top level parser routine. */
76{
77 int comma;
78 SymEntry* Entry;
79
80 /* Go... */
81 NextToken ();
82 NextToken ();
83
84 /* Parse until end of input */
85 while (CurTok.Tok != TOK_CEOF) {
86
87 DeclSpec Spec;
88
89 /* Check for empty statements */
90 if (CurTok.Tok == TOK_SEMI) {
91 NextToken ();
92 continue;
93 }
94
95 /* Disallow ASM statements on global level */
96 if (CurTok.Tok == TOK_ASM) {
97 Error ("__asm__ is not allowed here");
98 /* Parse and remove the statement for error recovery */
99 AsmStatement ();
100 ConsumeSemi ();
101 RemoveGlobalCode ();
102 continue;
103 }
104
105 /* Check for a #pragma */
106 if (CurTok.Tok == TOK_PRAGMA) {
107 DoPragma ();
108 continue;
109 }
110
111 /* Read variable defs and functions */
112 ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
113
114 /* Don't accept illegal storage classes */
115 if ((Spec.StorageClass & SC_TYPE) == 0) {
116 if ((Spec.StorageClass & SC_AUTO) != 0 ||
117 (Spec.StorageClass & SC_REGISTER) != 0) {
118 Error ("Illegal storage class");
119 Spec.StorageClass = SC_EXTERN | SC_STATIC;
120 }
121 }
122
123 /* Check if this is only a type declaration */
124 if (CurTok.Tok == TOK_SEMI) {
125 CheckEmptyDecl (&Spec);
126 NextToken ();
127 continue;
128 }
129
130 /* Read declarations for this type */
131 Entry = 0;
132 comma = 0;
133 while (1) {
134
135 Declaration Decl;
136
137 /* Read the next declaration */
138 ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
139 if (Decl.Ident[0] == '\0') {
140 NextToken ();
141 break;
142 }
143
144 /* Check if we must reserve storage for the variable. We do this,
145 **
146 ** - if it is not a typedef or function,
147 ** - if we don't had a storage class given ("int i")
148 ** - if the storage class is explicitly specified as static,
149 ** - or if there is an initialization.
150 **
151 ** This means that "extern int i;" will not get storage allocated.
152 */
153 if ((Decl.StorageClass & SC_FUNC) != SC_FUNC &&
154 (Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF &&
155 ((Spec.Flags & DS_DEF_STORAGE) != 0 ||
156 (Decl.StorageClass & (SC_EXTERN|SC_STATIC)) == SC_STATIC ||
157 ((Decl.StorageClass & SC_EXTERN) != 0 &&
158 CurTok.Tok == TOK_ASSIGN))) {
159
160 /* We will allocate storage */
161 Decl.StorageClass |= SC_STORAGE;
162 }
163
164 /* If this is a function declarator that is not followed by a comma
165 ** or semicolon, it must be followed by a function body. If this is
166 ** the case, convert an empty parameter list into one accepting no
167 ** parameters (same as void) as required by the standard.
168 */
169 if ((Decl.StorageClass & SC_FUNC) != 0 &&
170 (CurTok.Tok != TOK_COMMA) &&
171 (CurTok.Tok != TOK_SEMI)) {
172
173 FuncDesc* D = GetFuncDesc (Decl.Type);
174
175 if (D->Flags & FD_EMPTY) {
176 D->Flags = (D->Flags & ~FD_EMPTY) | FD_VOID_PARAM;
177 }
178 }
179
180 /* Add an entry to the symbol table */
181 Entry = AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass);
182
183 /* Add declaration attributes */
184 SymUseAttr (Entry, &Decl);
185
186 /* Reserve storage for the variable if we need to */
187 if (Decl.StorageClass & SC_STORAGE) {
188
189 /* Get the size of the variable */
190 unsigned Size = SizeOf (Decl.Type);
191
192 /* Allow initialization */
193 if (CurTok.Tok == TOK_ASSIGN) {
194
195 /* This is a definition */
196 if (SymIsDef (Entry)) {
197 Error ("Global variable '%s' has already been defined",
198 Entry->Name);
199 }
200 Entry->Flags |= SC_DEF;
201
202 /* We cannot initialize types of unknown size, or
203 ** void types in ISO modes.
204 */
205 if (Size == 0) {
206 if (!IsTypeVoid (Decl.Type)) {
207 if (!IsTypeArray (Decl.Type)) {
208 /* Size is unknown and not an array */
209 Error ("Variable '%s' has unknown size", Decl.Ident);
210 }
211 } else if (IS_Get (&Standard) != STD_CC65) {
212 /* We cannot declare variables of type void */
213 Error ("Illegal type for variable '%s'", Decl.Ident);
214 }
215 }
216
217 /* Switch to the data or rodata segment. For arrays, check
218 ** the element qualifiers, since not the array but its
219 ** elements are const.
220 */
221 if (IsQualConst (GetBaseElementType (Decl.Type))) {
222 g_userodata ();
223 } else {
224 g_usedata ();
225 }
226
227 /* Define a label */
228 g_defgloblabel (Entry->Name);
229
230 /* Skip the '=' */
231 NextToken ();
232
233 /* Parse the initialization */
234 ParseInit (Entry->Type);
235 } else {
236
237 if (IsTypeVoid (Decl.Type)) {
238 /* We cannot declare variables of type void */
239 Error ("Illegal type for variable '%s'", Decl.Ident);
240 Entry->Flags &= ~(SC_STORAGE | SC_DEF);
241 } else if (Size == 0) {
242 /* Size is unknown. Is it an array? */
243 if (!IsTypeArray (Decl.Type)) {
244 Error ("Variable '%s' has unknown size", Decl.Ident);
245 }
246 Entry->Flags &= ~(SC_STORAGE | SC_DEF);
247 } else {
248 /* A global (including static) uninitialized variable is
249 ** only a tentative definition. For example, this is valid:
250 ** int i;
251 ** int i;
252 ** static int j;
253 ** static int j = 42;
254 ** Code for them will be generated by FinishCompile().
255 ** For now, just save the BSS segment name
256 ** (can be set by #pragma bss-name).
257 */
258 const char* bssName = GetSegName (SEG_BSS);
259
260 if (Entry->V.BssName && strcmp (Entry->V.BssName, bssName) != 0) {
261 Error ("Global variable '%s' already was defined in the '%s' segment.",
262 Entry->Name, Entry->V.BssName);
263 }
264 Entry->V.BssName = xstrdup (bssName);
265 }
266 }
267
268 }
269
270 /* Check for end of declaration list */
271 if (CurTok.Tok == TOK_COMMA) {
272 NextToken ();
273 comma = 1;
274 } else {
275 break;
276 }
277 }
278
279 /* Function declaration? */
280 if (Entry && IsTypeFunc (Entry->Type)) {
281
282 /* Function */
283 if (!comma) {
284 if (CurTok.Tok == TOK_SEMI) {
285 /* Prototype only */
286 NextToken ();
287 } else {
288
289 /* Function body. Check for duplicate function definitions */
290 if (SymIsDef (Entry)) {
291 Error ("Body for function '%s' has already been defined",
292 Entry->Name);
293 }
294
295 /* Parse the function body */
296 NewFunc (Entry);
297 }
298 }
299
300 } else {
301
302 /* Must be followed by a semicolon */
303 ConsumeSemi ();
304
305 }
306 }
307}
308
309
310
311void Compile (const char* FileName)
312/* Top level compile routine. Will setup things and call the parser. */
313{
314 char DateStr[32];
315 char TimeStr[32];
316 time_t Time;
317 struct tm* TM;
318
319 /* Since strftime is locale dependent, we need the abbreviated month names
320 ** in English.
321 */
322 static const char MonthNames[12][4] = {
323 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
324 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
325 };
326
327 /* Add macros that are always defined */
328 DefineNumericMacro ("__CC65__", GetVersionAsNumber ());
329
330 /* Language standard that is supported */
331 DefineNumericMacro ("__CC65_STD_C89__", STD_C89);
332 DefineNumericMacro ("__CC65_STD_C99__", STD_C99);
333 DefineNumericMacro ("__CC65_STD_CC65__", STD_CC65);
334 DefineNumericMacro ("__CC65_STD__", IS_Get (&Standard));
335
336 /* Optimization macros. Since no source code has been parsed for now, the
337 ** IS_Get functions access the values in effect now, regardless of any
338 ** changes using #pragma later.
339 */
340 if (IS_Get (&Optimize)) {
341 DefineNumericMacro ("__OPT__", 1);
342 }
343 {
344 long CodeSize = IS_Get (&CodeSizeFactor);
345 if (CodeSize > 100) {
346 DefineNumericMacro ("__OPT_i__", CodeSize);
347 }
348 }
349 if (IS_Get (&EnableRegVars)) {
350 DefineNumericMacro ("__OPT_r__", 1);
351 }
352 if (IS_Get (&InlineStdFuncs)) {
353 DefineNumericMacro ("__OPT_s__", 1);
354 }
355 if (IS_Get (&EagerlyInlineFuncs)) {
356 DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1);
357 }
358
359 /* __TIME__ and __DATE__ macros */
360 Time = time (0);
361 TM = localtime (&Time);
362 xsprintf (DateStr, sizeof (DateStr), "\"%s %2d %d\"",
363 MonthNames[TM->tm_mon], TM->tm_mday, TM->tm_year + 1900);
364 strftime (TimeStr, sizeof (TimeStr), "\"%H:%M:%S\"", TM);
365 DefineTextMacro ("__DATE__", DateStr);
366 DefineTextMacro ("__TIME__", TimeStr);
367
368 /* Other standard macros */
369 /* DefineNumericMacro ("__STDC__", 1); <- not now */
370 DefineNumericMacro ("__STDC_HOSTED__", 1);
371
372 /* Create the base lexical level */
373 EnterGlobalLevel ();
374
375 /* Create the global code and data segments */
376 CreateGlobalSegments ();
377
378 /* Initialize the literal pool */
379 InitLiteralPool ();
380
381 /* Generate the code generator preamble */
382 g_preamble ();
383
384 /* Open the input file */
385 OpenMainFile (FileName);
386
387 /* Are we supposed to compile or just preprocess the input? */
388 if (PreprocessOnly) {
389
390 /* Open the file */
391 OpenOutputFile ();
392
393 /* Preprocess each line and write it to the output file */
394 while (NextLine ()) {
395 Preprocess ();
396 WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
397 }
398
399 /* Close the output file */
400 CloseOutputFile ();
401
402 } else {
403
404 /* Ok, start the ball rolling... */
405 Parse ();
406
407 }
408
409 if (Debug) {
410 PrintMacroStats (stdout);
411 }
412
413 /* Print an error report */
414 ErrorReport ();
415}
416
417
418
419void FinishCompile (void)
420/* Emit literals, externals, debug info, do cleanup and optimizations */
421{
422 SymEntry* Entry;
423
424 /* Reset the BSS segment name to its default; so that the below strcmp()
425 ** will work as expected, at the beginning of the list of variables
426 */
427 SetSegName (SEG_BSS, SEGNAME_BSS);
428
429 /* Walk over all global symbols:
430 ** - for functions, do clean-up and optimizations
431 ** - generate code for uninitialized global variables
432 */
433 for (Entry = GetGlobalSymTab ()->SymHead; Entry; Entry = Entry->NextSym) {
434 if (SymIsOutputFunc (Entry)) {
435 /* Function which is defined and referenced or extern */
436 MoveLiteralPool (Entry->V.F.LitPool);
437 CS_MergeLabels (Entry->V.F.Seg->Code);
438 RunOpt (Entry->V.F.Seg->Code);
439 } else if ((Entry->Flags & (SC_STORAGE | SC_DEF | SC_STATIC)) == (SC_STORAGE | SC_STATIC)) {
440 /* Assembly definition of uninitialized global variable */
441
442 /* Set the segment name only when it changes */
443 if (strcmp (GetSegName (SEG_BSS), Entry->V.BssName) != 0) {
444 SetSegName (SEG_BSS, Entry->V.BssName);
445 g_segname (SEG_BSS);
446 }
447 g_usebss ();
448 g_defgloblabel (Entry->Name);
449 g_res (SizeOf (Entry->Type));
450 /* Mark as defined; so that it will be exported, not imported */
451 Entry->Flags |= SC_DEF;
452 }
453 }
454
455 /* Output the literal pool */
456 OutputLiteralPool ();
457
458 /* Emit debug infos if enabled */
459 EmitDebugInfo ();
460
461 /* Write imported/exported symbols */
462 EmitExternals ();
463
464 /* Leave the main lexical level */
465 LeaveGlobalLevel ();
466}
467