X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcompile.c;h=48a5c29d35adca95c566a0adf9f490b041ffbab9;hb=a780df1fe1ae5373b266095d37754e318b52d00d;hp=8475657a4f0df470223202f35e10c8ee9c52a2cd;hpb=a1d7fed1286d6950a39533badec3bc169b4695ce;p=cc65 diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 8475657a4..48a5c29d3 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -1,15 +1,15 @@ /*****************************************************************************/ /* */ -/* compile.c */ +/* compile.c */ /* */ -/* Top level compiler subroutine */ +/* Top level compiler subroutine */ /* */ /* */ /* */ -/* (C) 2000-2008 Ullrich von Bassewitz */ -/* Roemerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2000-2013, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -46,6 +46,7 @@ #include "asmlabel.h" #include "asmstmt.h" #include "codegen.h" +#include "codeopt.h" #include "compile.h" #include "declare.h" #include "error.h" @@ -55,6 +56,7 @@ #include "input.h" #include "litpool.h" #include "macrotab.h" +#include "output.h" #include "pragma.h" #include "preproc.h" #include "standard.h" @@ -63,7 +65,7 @@ /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -81,32 +83,34 @@ static void Parse (void) /* Parse until end of input */ while (CurTok.Tok != TOK_CEOF) { - DeclSpec Spec; - Declaration Decl; + DeclSpec Spec; - /* Check for empty statements */ - if (CurTok.Tok == TOK_SEMI) { - NextToken (); - continue; - } + /* Check for empty statements */ + if (CurTok.Tok == TOK_SEMI) { + NextToken (); + continue; + } - /* Check for an ASM statement (which is allowed also on global level) */ - if (CurTok.Tok == TOK_ASM) { - AsmStatement (); - ConsumeSemi (); - continue; - } + /* Disallow ASM statements on global level */ + if (CurTok.Tok == TOK_ASM) { + Error ("__asm__ is not allowed here"); + /* Parse and remove the statement for error recovery */ + AsmStatement (); + ConsumeSemi (); + RemoveGlobalCode (); + continue; + } - /* Check for a #pragma */ - if (CurTok.Tok == TOK_PRAGMA) { - DoPragma (); - continue; - } + /* Check for a #pragma */ + if (CurTok.Tok == TOK_PRAGMA) { + DoPragma (); + continue; + } - /* Read variable defs and functions */ - ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT); + /* Read variable defs and functions */ + ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT); - /* Don't accept illegal storage classes */ + /* Don't accept illegal storage classes */ if ((Spec.StorageClass & SC_TYPE) == 0) { if ((Spec.StorageClass & SC_AUTO) != 0 || (Spec.StorageClass & SC_REGISTER) != 0) { @@ -115,45 +119,52 @@ static void Parse (void) } } - /* Check if this is only a type declaration */ - if (CurTok.Tok == TOK_SEMI) { - CheckEmptyDecl (&Spec); - NextToken (); - continue; - } - - /* Read declarations for this type */ - Entry = 0; - comma = 0; - while (1) { - - /* Read the next declaration */ - ParseDecl (&Spec, &Decl, DM_NEED_IDENT); - if (Decl.Ident[0] == '\0') { - NextToken (); - break; - } + /* Check if this is only a type declaration */ + if (CurTok.Tok == TOK_SEMI) { + CheckEmptyDecl (&Spec); + NextToken (); + continue; + } + + /* Read declarations for this type */ + Entry = 0; + comma = 0; + while (1) { + + Declaration Decl; + + /* Read the next declaration */ + ParseDecl (&Spec, &Decl, DM_NEED_IDENT); + if (Decl.Ident[0] == '\0') { + NextToken (); + break; + } /* Check if we must reserve storage for the variable. We do this, - * if it is not a typedef or function, if we don't had a storage - * class given ("int i") or if the storage class is explicitly - * specified as static. This means that "extern int i" will not - * get storage allocated. - */ - if ((Decl.StorageClass & SC_FUNC) == 0 && - (Decl.StorageClass & SC_TYPEDEF) == 0 && - ((Spec.Flags & DS_DEF_STORAGE) != 0 || - (Decl.StorageClass & (SC_STATIC | SC_EXTERN)) == SC_STATIC)) { + ** + ** - if it is not a typedef or function, + ** - if we don't had a storage class given ("int i") + ** - if the storage class is explicitly specified as static, + ** - or if there is an initialization. + ** + ** This means that "extern int i;" will not get storage allocated. + */ + if ((Decl.StorageClass & SC_FUNC) != SC_FUNC && + (Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF && + ((Spec.Flags & DS_DEF_STORAGE) != 0 || + (Decl.StorageClass & (SC_EXTERN|SC_STATIC)) == SC_STATIC || + ((Decl.StorageClass & SC_EXTERN) != 0 && + CurTok.Tok == TOK_ASSIGN))) { /* We will allocate storage */ - Decl.StorageClass |= SC_STORAGE | SC_DEF; - } + Decl.StorageClass |= SC_STORAGE; + } /* If this is a function declarator that is not followed by a comma - * or semicolon, it must be followed by a function body. If this is - * the case, convert an empty parameter list into one accepting no - * parameters (same as void) as required by the standard. - */ + ** or semicolon, it must be followed by a function body. If this is + ** the case, convert an empty parameter list into one accepting no + ** parameters (same as void) as required by the standard. + */ if ((Decl.StorageClass & SC_FUNC) != 0 && (CurTok.Tok != TOK_COMMA) && (CurTok.Tok != TOK_SEMI)) { @@ -164,96 +175,105 @@ static void Parse (void) } } - /* Add an entry to the symbol table */ - Entry = AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass); - - /* Reserve storage for the variable if we need to */ - if (Decl.StorageClass & SC_STORAGE) { - - /* Get the size of the variable */ - unsigned Size = SizeOf (Decl.Type); - - /* Allow initialization */ - if (CurTok.Tok == TOK_ASSIGN) { - - /* We cannot initialize types of unknown size, or - * void types in non ANSI mode. - */ - if (Size == 0) { - if (!IsTypeVoid (Decl.Type)) { - if (!IsTypeArray (Decl.Type)) { - /* Size is unknown and not an array */ - Error ("Variable `%s' has unknown size", Decl.Ident); - } - } else if (IS_Get (&Standard) != STD_CC65) { - /* We cannot declare variables of type void */ - Error ("Illegal type for variable `%s'", Decl.Ident); - } - } - - /* Switch to the data or rodata segment */ - if (IsQualConst (Decl.Type)) { - g_userodata (); - } else { - g_usedata (); - } - - /* Define a label */ - g_defgloblabel (Entry->Name); - - /* Skip the '=' */ - NextToken (); - - /* Parse the initialization */ - ParseInit (Entry->Type); - } else { - - if (IsTypeVoid (Decl.Type)) { - /* We cannot declare variables of type void */ - Error ("Illegal type for variable `%s'", Decl.Ident); + /* Add an entry to the symbol table */ + Entry = AddGlobalSym (Decl.Ident, Decl.Type, Decl.StorageClass); + + /* Add declaration attributes */ + SymUseAttr (Entry, &Decl); + + /* Reserve storage for the variable if we need to */ + if (Decl.StorageClass & SC_STORAGE) { + + /* Get the size of the variable */ + unsigned Size = SizeOf (Decl.Type); + + /* Allow initialization */ + if (CurTok.Tok == TOK_ASSIGN) { + + /* This is a definition */ + if (SymIsDef (Entry)) { + Error ("Global variable `%s' has already been defined", + Entry->Name); + } + Entry->Flags |= SC_DEF; + + /* We cannot initialize types of unknown size, or + ** void types in ISO modes. + */ + if (Size == 0) { + if (!IsTypeVoid (Decl.Type)) { + if (!IsTypeArray (Decl.Type)) { + /* Size is unknown and not an array */ + Error ("Variable `%s' has unknown size", Decl.Ident); + } + } else if (IS_Get (&Standard) != STD_CC65) { + /* We cannot declare variables of type void */ + Error ("Illegal type for variable `%s'", Decl.Ident); + } + } + + /* Switch to the data or rodata segment. For arrays, check + ** the element qualifiers, since not the array but its + ** elements are const. + */ + if (IsQualConst (GetBaseElementType (Decl.Type))) { + g_userodata (); + } else { + g_usedata (); + } + + /* Define a label */ + g_defgloblabel (Entry->Name); + + /* Skip the '=' */ + NextToken (); + + /* Parse the initialization */ + ParseInit (Entry->Type); + } else { + + if (IsTypeVoid (Decl.Type)) { + /* We cannot declare variables of type void */ + Error ("Illegal type for variable `%s'", Decl.Ident); Entry->Flags &= ~(SC_STORAGE | SC_DEF); } else if (Size == 0) { - /* Size is unknown. Is it an array? */ + /* Size is unknown. Is it an array? */ if (!IsTypeArray (Decl.Type)) { Error ("Variable `%s' has unknown size", Decl.Ident); } Entry->Flags &= ~(SC_STORAGE | SC_DEF); - } - - /* Allocate storage if it is still needed */ - if (Entry->Flags & SC_STORAGE) { - - /* Switch to the BSS segment */ - g_usebss (); - - /* Define a label */ - g_defgloblabel (Entry->Name); - - /* Allocate space for uninitialized variable */ - g_res (Size); } - } - } + /* A global (including static) uninitialized variable + ** is only a tentative definition. For example, this is valid: + ** int i; + ** int i; + ** static int j; + ** static int j = 42; + ** Code for these will be generated in FinishCompile. + */ + } + + } - /* Check for end of declaration list */ - if (CurTok.Tok == TOK_COMMA) { - NextToken (); - comma = 1; - } else { - break; - } - } + /* Check for end of declaration list */ + if (CurTok.Tok == TOK_COMMA) { + NextToken (); + comma = 1; + } else { + break; + } + } - /* Function declaration? */ - if (Entry && IsTypeFunc (Entry->Type)) { + /* Function declaration? */ + if (Entry && IsTypeFunc (Entry->Type)) { - /* Function */ - if (!comma) { - if (CurTok.Tok == TOK_SEMI) { - /* Prototype only */ - NextToken (); - } else { + /* Function */ + if (!comma) { + if (CurTok.Tok == TOK_SEMI) { + /* Prototype only */ + NextToken (); + } else { /* Function body. Check for duplicate function definitions */ if (SymIsDef (Entry)) { @@ -263,15 +283,15 @@ static void Parse (void) /* Parse the function body */ NewFunc (Entry); - } - } + } + } - } else { + } else { - /* Must be followed by a semicolon */ - ConsumeSemi (); + /* Must be followed by a semicolon */ + ConsumeSemi (); - } + } } } @@ -286,15 +306,15 @@ void Compile (const char* FileName) struct tm* TM; /* Since strftime is locale dependent, we need the abbreviated month names - * in english. - */ + ** in English. + */ static const char MonthNames[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* Add macros that are always defined */ - DefineNumericMacro ("__CC65__", VERSION); + DefineNumericMacro ("__CC65__", GetVersionAsNumber ()); /* Language standard that is supported */ DefineNumericMacro ("__CC65_STD_C89__", STD_C89); @@ -303,21 +323,21 @@ void Compile (const char* FileName) DefineNumericMacro ("__CC65_STD__", IS_Get (&Standard)); /* Optimization macros. Since no source code has been parsed for now, the - * IS_Get functions access the values in effect now, regardless of any - * changes using #pragma later. - */ + ** IS_Get functions access the values in effect now, regardless of any + ** changes using #pragma later. + */ if (IS_Get (&Optimize)) { long CodeSize = IS_Get (&CodeSizeFactor); - DefineNumericMacro ("__OPT__", 1); - if (CodeSize > 100) { - DefineNumericMacro ("__OPT_i__", CodeSize); - } - if (IS_Get (&EnableRegVars)) { - DefineNumericMacro ("__OPT_r__", 1); - } - if (IS_Get (&InlineStdFuncs)) { - DefineNumericMacro ("__OPT_s__", 1); - } + DefineNumericMacro ("__OPT__", 1); + if (CodeSize > 100) { + DefineNumericMacro ("__OPT_i__", CodeSize); + } + if (IS_Get (&EnableRegVars)) { + DefineNumericMacro ("__OPT_r__", 1); + } + if (IS_Get (&InlineStdFuncs)) { + DefineNumericMacro ("__OPT_s__", 1); + } } /* __TIME__ and __DATE__ macros */ @@ -329,12 +349,19 @@ void Compile (const char* FileName) DefineTextMacro ("__DATE__", DateStr); DefineTextMacro ("__TIME__", TimeStr); - /* Initialize the literal pool */ - InitLiteralPool (); + /* Other standard macros */ + /* DefineNumericMacro ("__STDC__", 1); <- not now */ + DefineNumericMacro ("__STDC_HOSTED__", 1); /* Create the base lexical level */ EnterGlobalLevel (); + /* Create the global code and data segments */ + CreateGlobalSegments (); + + /* Initialize the literal pool */ + InitLiteralPool (); + /* Generate the code generator preamble */ g_preamble (); @@ -344,35 +371,28 @@ void Compile (const char* FileName) /* Are we supposed to compile or just preprocess the input? */ if (PreprocessOnly) { + /* Open the file */ + OpenOutputFile (); + + /* Preprocess each line and write it to the output file */ while (NextLine ()) { Preprocess (); - printf ("%.*s\n", SB_GetLen (Line), SB_GetConstBuf (Line)); + WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } - if (Debug) { - PrintMacroStats (stdout); - } + /* Close the output file */ + CloseOutputFile (); } else { /* Ok, start the ball rolling... */ Parse (); - /* Dump the literal pool. */ - DumpLiteralPool (); - - /* Write imported/exported symbols */ - EmitExternals (); - - if (Debug) { - PrintLiteralPoolStats (stdout); - PrintMacroStats (stdout); - } - } - /* Leave the main lexical level */ - LeaveGlobalLevel (); + if (Debug) { + PrintMacroStats (stdout); + } /* Print an error report */ ErrorReport (); @@ -380,4 +400,40 @@ void Compile (const char* FileName) +void FinishCompile (void) +/* Emit literals, externals, debug info, do cleanup and optimizations */ +{ + SymEntry* Entry; + + /* Walk over all global symbols: + ** - for functions do cleanup, optimizations ... + ** - generate code for uninitialized global variables + */ + for (Entry = GetGlobalSymTab ()->SymHead; Entry; Entry = Entry->NextSym) { + if (SymIsOutputFunc (Entry)) { + /* Function which is defined and referenced or extern */ + MoveLiteralPool (Entry->V.F.LitPool); + CS_MergeLabels (Entry->V.F.Seg->Code); + RunOpt (Entry->V.F.Seg->Code); + } else if ((Entry->Flags & (SC_STORAGE | SC_DEF | SC_STATIC)) == (SC_STORAGE | SC_STATIC)) { + /* Tentative definition of uninitialized global variable */ + g_usebss (); + g_defgloblabel (Entry->Name); + g_res (SizeOf (Entry->Type)); + /* Mark as defined, so that it will be exported not imported */ + Entry->Flags |= SC_DEF; + } + } + + /* Output the literal pool */ + OutputLiteralPool (); + + /* Emit debug infos if enabled */ + EmitDebugInfo (); + + /* Write imported/exported symbols */ + EmitExternals (); + /* Leave the main lexical level */ + LeaveGlobalLevel (); +}