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 | |
74 | static 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 | |
311 | void 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 | |
419 | void 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 | |