diff --git a/Makefile b/Makefile
index b7e1157..b754bf9 100644
--- a/Makefile
+++ b/Makefile
@@ -26,9 +26,6 @@ all: $(LIBNAME) $(OBJ) Makefile
%.o: %.cpp
$(CXX) $(CXXFLAGS) -o $@ -c $<
-%.o: %.c
- $(CXX) $(CXXFLAGS) -o $@ -c $<
-
$(LIBNAME):
make -C $(LIBDIR) all
diff --git a/PropellerCompiler.sln b/PropellerCompiler.sln
index fead7cc..8069b73 100644
--- a/PropellerCompiler.sln
+++ b/PropellerCompiler.sln
@@ -1,7 +1,9 @@
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}"
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcxproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/PropellerCompiler/CompileDatBlocks.cpp b/PropellerCompiler/CompileDatBlocks.cpp
index be612ac..0acf0f0 100644
--- a/PropellerCompiler/CompileDatBlocks.cpp
+++ b/PropellerCompiler/CompileDatBlocks.cpp
@@ -97,7 +97,7 @@ bool CompileDatBlocks_Enter(int value, int count, int size)
bool CompileDatBlocks_Advance(bool bSymbol, bool bResSymbol, int size)
{
int testVal = (1 << size) - 1;
- while (1)
+ for (;;)
{
if ((g_pCompilerData->obj_ptr & testVal) == 0)
{
diff --git a/PropellerCompiler/CompileExpression.cpp b/PropellerCompiler/CompileExpression.cpp
index ef229cc..fbb1d6d 100644
--- a/PropellerCompiler/CompileExpression.cpp
+++ b/PropellerCompiler/CompileExpression.cpp
@@ -155,7 +155,7 @@ bool CompileSubExpression(int precedence)
}
}
- while (1)
+ for (;;)
{
bool bEof = false;
if (!g_pElementizer->GetNext(bEof))
@@ -230,7 +230,7 @@ bool CompileTerm_ConStr()
}
// get the string into the string constant buffer
- while(1)
+ for (;;)
{
if (!GetTryValue(true, false))
{
@@ -334,7 +334,7 @@ bool CompileTerm_ObjPub(unsigned char anchor, int value)
int objPubValue = g_pElementizer->GetValue();
- // compile any paramaters the pub has
+ // compile any parameters the pub has
if (!CompileParameters((objPubValue & 0x0000FF00) >> 8))
{
return false;
@@ -424,7 +424,7 @@ bool CompileLook(int column, int param)
{
return false;
}
- if (!CompileExpression()) // compile primarey value
+ if (!CompileExpression()) // compile primary value
{
return false;
}
@@ -433,7 +433,7 @@ bool CompileLook(int column, int param)
return false;
}
- while (1)
+ for (;;)
{
bool bRange = false;
if (!CompileRange(bRange)) // compile (next) value/range
diff --git a/PropellerCompiler/CompileInstruction.cpp b/PropellerCompiler/CompileInstruction.cpp
index 6005485..41ec436 100644
--- a/PropellerCompiler/CompileInstruction.cpp
+++ b/PropellerCompiler/CompileInstruction.cpp
@@ -36,7 +36,7 @@ bool CompileInst_NextQuit(int value)
int caseDepth = 0;
// find repeat block
- while(1)
+ for (;;)
{
if (blockNestPtr == 0)
{
diff --git a/PropellerCompiler/DistillObjects.cpp b/PropellerCompiler/DistillObjects.cpp
index f2f79b5..f3ef417 100644
--- a/PropellerCompiler/DistillObjects.cpp
+++ b/PropellerCompiler/DistillObjects.cpp
@@ -34,6 +34,9 @@ bool DistillSetup_Enter(unsigned short value)
return true;
}
+// create a table of all objects with their offsets and sub objects
+// each entry contains:
+// id, offset, number sub objects, [sub object ids]
bool DistillSetup_Record(short id, unsigned short offset, unsigned short& subObjectId)
{
if (!DistillSetup_Enter(id))
@@ -83,6 +86,9 @@ bool DistillSetup()
return false;
}
+ // Clear all the objects table of offsets to their sub objects
+ // this needs to be done so that objects will binary compare with each other properly
+ // these offsets get replaced in the reconnect step
int disPtr = 0;
while (disPtr < g_pCompilerData->dis_ptr)
{
@@ -109,6 +115,8 @@ bool DistillSetup()
return true;
}
+// update all objects of the given id to the new id
+// also flags them as "distilled" with the upper bit being on
void DistillEliminate_Update(unsigned short objectId, int newDisPtr)
{
int disPtr = 0;
@@ -267,7 +275,7 @@ void DistillReconnect(int disPtr = 0)
// find offset of sub-object
int scanDisPtr = 0;
- while(1)
+ for (;;)
{
if (g_pCompilerData->dis[scanDisPtr] == subObjectId)
{
diff --git a/PropellerCompiler/Elementizer.cpp b/PropellerCompiler/Elementizer.cpp
index 28d10f7..0767966 100644
--- a/PropellerCompiler/Elementizer.cpp
+++ b/PropellerCompiler/Elementizer.cpp
@@ -96,7 +96,7 @@ bool Elementizer::GetNext(bool& bEof)
m_currentSymbol[0] = 0;
int symbolOffset = 0;
- while(1)
+ for (;;)
{
char currentChar = pSource[m_sourceOffset++];
@@ -281,7 +281,7 @@ bool Elementizer::GetNext(bool& bEof)
bDocComment = true;
g_pCompilerData->doc_flag = true;
}
- while(1)
+ for (;;)
{
currentChar = pSource[m_sourceOffset++];
if (currentChar == 0)
@@ -318,7 +318,7 @@ bool Elementizer::GetNext(bool& bEof)
m_sourceOffset++; // skip over end if present
}
}
- while(1)
+ for (;;)
{
currentChar = pSource[m_sourceOffset++];
if (currentChar == 0)
diff --git a/PropellerCompiler/InstructionBlockCompiler.cpp b/PropellerCompiler/InstructionBlockCompiler.cpp
index 4ef70c4..3f0e300 100644
--- a/PropellerCompiler/InstructionBlockCompiler.cpp
+++ b/PropellerCompiler/InstructionBlockCompiler.cpp
@@ -337,7 +337,7 @@ bool CompileCase(int column, int param)
g_pCompilerData->error_msg = g_pErrorStrings[error_loxce];
return false;
}
- while (1)
+ for (;;)
{
bool bRange = false;
if (!CompileRange(bRange))
@@ -442,8 +442,8 @@ bool CompileCase(int column, int param)
}
else
{
- // skip over range/values(s), allready compiled
- while (1)
+ // skip over range/values(s), already compiled
+ for (;;)
{
if (!SkipRange())
{
@@ -493,7 +493,7 @@ bool CompileRepeatPlain(int column, int param)
{
param = param; // stop warning
- BlockStack_Write(2, g_pCompilerData->obj_ptr); // set revearse address
+ BlockStack_Write(2, g_pCompilerData->obj_ptr); // set reverse address
if (!s_bHasPost)
{
BlockStack_Write(0, g_pCompilerData->obj_ptr); // set plain 'next' address
@@ -830,7 +830,7 @@ bool OptimizeBlock(int column, int param, bool (*pCompileFunction)(int, int))
int savedObjPtr = g_pCompilerData->obj_ptr;
int size = 0;
- while(1)
+ for (;;)
{
g_pElementizer->SetSourcePtr(savedSourcePtr);
g_pCompilerData->obj_ptr = savedObjPtr;
diff --git a/PropellerCompiler/Makefile b/PropellerCompiler/Makefile
index c8c760d..498eb1a 100644
--- a/PropellerCompiler/Makefile
+++ b/PropellerCompiler/Makefile
@@ -24,6 +24,7 @@ OBJ=$(SRCDIR)/BlockNestStackRoutines.o \
$(SRCDIR)/StringConstantRoutines.o \
$(SRCDIR)/SymbolEngine.o \
$(SRCDIR)/Utilities.o \
+ $(SRCDIR)/UnusedMethodUtils.o \
$(SRCDIR)/PropellerCompiler.o \
diff --git a/PropellerCompiler/PropellerCompiler.cpp b/PropellerCompiler/PropellerCompiler.cpp
index a0c71d4..7603a7c 100644
--- a/PropellerCompiler/PropellerCompiler.cpp
+++ b/PropellerCompiler/PropellerCompiler.cpp
@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////
// //
// Propeller Spin/PASM Compiler //
-// (c)2012 Parallax Inc. DBA Parallax Semiconductor. //
+// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. //
// Adapted from Chip Gracey's x86 asm code by Roy Eltham //
// See end of file for terms of use. //
// //
@@ -19,6 +19,7 @@
#include "SymbolEngine.h"
#include "Elementizer.h"
#include "ErrorStrings.h"
+#include "UnusedMethodUtils.h"
//////////////////////////////////////////
// declarations for internal functions
@@ -460,7 +461,7 @@ bool CompileConBlocks(int pass)
return true;
}
-bool CompileSubBlocksId_Compile(int blockType, bool &bFirst)
+bool CompileSubBlocksId_Compile(int blockType, bool &bFirst, int &nMethodIndex)
{
bool bEof = false;
g_pElementizer->Reset();
@@ -631,36 +632,40 @@ bool CompileSubBlocksId_Compile(int blockType, bool &bFirst)
}
}
- // enter sub symbol
- int value = params;
- value <<= 8;
- value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF;
- g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_sub, value, blockType);
+ if (!g_pCompilerData->bFinalCompile || IsMethodUsed(g_pCompilerData->current_filename, nMethodIndex))
+ {
+ // enter sub symbol
+ int value = params;
+ value <<= 8;
+ value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF;
+ g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_sub, value, blockType);
#ifdef RPE_DEBUG
- printf("Pub/Pri %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, params, g_pCompilerData->obj_ptr);
+ printf("Pub/Pri %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, params, g_pCompilerData->obj_ptr);
#endif
- if (!g_pCompilerData->bDATonly)
- {
- // enter locals count into index
- EnterObjLong(locals<<16);
- }
+ if (!g_pCompilerData->bDATonly)
+ {
+ // enter locals count into index (shifted up 16 to leave space for the sub offset which will be fixed up later)
+ EnterObjLong(locals<<16);
+ }
- if (blockType == block_pub)
- {
- if (!AddSymbolToPubConList())
+ if (blockType == block_pub)
{
- return false;
+ if (!AddSymbolToPubConList())
+ {
+ return false;
+ }
+ if (!AddPubConListByte(params))
+ {
+ return false;
+ }
}
- if (!AddPubConListByte(params))
+ if (bFirst == false)
{
- return false;
+ g_pCompilerData->first_pub_parameters = params;
+ bFirst = true;
}
}
- if (bFirst == false)
- {
- g_pCompilerData->first_pub_parameters = params;
- bFirst = true;
- }
+ nMethodIndex++;
}
else
{
@@ -682,7 +687,8 @@ bool CompileSubBlocksId_Compile(int blockType, bool &bFirst)
bool CompileSubBlocksId()
{
bool bFirst = false;
- if (!CompileSubBlocksId_Compile(block_pub, bFirst))
+ int nMethodIndex = 0;
+ if (!CompileSubBlocksId_Compile(block_pub, bFirst, nMethodIndex))
{
return false;
}
@@ -693,7 +699,7 @@ bool CompileSubBlocksId()
g_pCompilerData->source_start = g_pCompilerData->source_finish;
return false;
}
- if (!CompileSubBlocksId_Compile(block_pri, bFirst))
+ if (!CompileSubBlocksId_Compile(block_pri, bFirst, nMethodIndex))
{
return false;
}
@@ -706,6 +712,7 @@ bool CompileObjBlocksId()
g_pCompilerData->obj_start = g_pCompilerData->obj_ptr;
g_pCompilerData->obj_count = 0;
g_pCompilerData->obj_files = 0;
+ g_pCompilerData->unused_obj_files = 0;
bool bEof = false;
g_pElementizer->Reset();
@@ -770,41 +777,52 @@ bool CompileObjBlocksId()
{
return false;
}
-
- // is it a new obj?
- if (objFileIndex == (g_pCompilerData->obj_files - 1))
+ if ( !g_pCompilerData->bFinalCompile || IsObjectUsed(&g_pCompilerData->obj_filenames[objFileIndex<<8]) )
{
- // reset instances
- g_pCompilerData->obj_instances[objFileIndex] = 0;
- }
+ // is it a new obj?
+ if (objFileIndex == (g_pCompilerData->obj_files - 1))
+ {
+ // reset instances
+ g_pCompilerData->obj_instances[objFileIndex] = 0;
+ }
- // enter obj symbol
- int value = objFileIndex;
- value <<= 8;
- value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF;
- g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_obj, value);
+ // enter obj symbol
+ int value = objFileIndex;
+ value <<= 8;
+ value |= (g_pCompilerData->obj_ptr >> 2) & 0xFF;
+ g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_obj, value);
#ifdef RPE_DEBUG
- printf("Obj %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, instanceCount, g_pCompilerData->obj_ptr);
+ printf("Obj %s %d (%d, %d)\n", g_pCompilerData->symbolBackup, value, instanceCount, g_pCompilerData->obj_ptr);
#endif
- for (int i=0; i < instanceCount; i++)
- {
- if (g_pCompilerData->obj_ptr < 256*4)
- {
- // enter locals count into index
- EnterObjLong(objFileIndex);
- g_pCompilerData->obj_count++;
- }
- else
+ for (int i=0; i < instanceCount; i++)
{
- g_pCompilerData->error = true;
- g_pCompilerData->error_msg = g_pErrorStrings[error_loxspoe];
- return false;
+ if (g_pCompilerData->obj_ptr < 256*4)
+ {
+ // enter object index into table
+ EnterObjLong(objFileIndex);
+ g_pCompilerData->obj_count++;
+ }
+ else
+ {
+ g_pCompilerData->error = true;
+ g_pCompilerData->error_msg = g_pErrorStrings[error_loxspoe];
+ return false;
+ }
}
- }
- // accumulate instances
- g_pCompilerData->obj_instances[objFileIndex] += instanceCount;
+ // accumulate instances
+ g_pCompilerData->obj_instances[objFileIndex] += instanceCount;
+ }
+ else
+ {
+ strcpy(&(g_pCompilerData->obj_unused[g_pCompilerData->unused_obj_files<<8]), &(g_pCompilerData->obj_filenames[objFileIndex<<8]));
+ int value = g_pCompilerData->unused_obj_files | 0x40;
+ value <<= 8;
+ g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, type_obj, value);
+ g_pCompilerData->unused_obj_files++;
+ g_pCompilerData->obj_files--;
+ }
if (!g_pElementizer->GetElement(type_end))
{
@@ -958,8 +976,8 @@ bool CompileObjSymbols()
#ifdef RPE_DEBUG
printf("objpub: %s %d \n", g_pCompilerData->symbolBackup, value);
#endif
- pData++; // adjust pointer to after param count
nPub++;
+ pData++; // adjust pointer to after param count
break;
}
else // handle objcon or objcon_float symbol
@@ -982,6 +1000,53 @@ bool CompileObjSymbols()
}
}
}
+
+ // now add any CON symbols from unused objects
+ for (int nUnusedFile = 0; nUnusedFile < g_pCompilerData->unused_obj_files; nUnusedFile++)
+ {
+ unsigned char* pData = 0;
+ int nDataSize = 0;
+ if (GetObjectPubConList(&(g_pCompilerData->obj_unused[nUnusedFile<<8]), &pData, &nDataSize))
+ {
+ unsigned char *pDataEnd = pData + nDataSize;
+ // go thru symbols validating them and adding them to the symbol table
+ while (pData < pDataEnd)
+ {
+ for (int i = 0; i < symbol_limit+1; i++)
+ {
+ if (!CheckWordChar((char)(*pData)))
+ {
+ CompileObjSymbol_BadObj(nFile);
+ return false;
+ }
+ g_pCompilerData->symbolBackup[i] = (char)(*pData);
+ pData++;
+ if (pData[0] < 18) // 0 to 15 = pub param count, 16 and 17 are constants
+ {
+ g_pCompilerData->symbolBackup[i+1] = (char)(0x40 | (nUnusedFile + 1));
+ g_pCompilerData->symbolBackup[i+2] = 0;
+ if (pData[0] < 16) // handle objpub symbol
+ {
+ // we don't add pubs in this case
+ pData++; // adjust pointer to after param count
+ break;
+ }
+ else // handle objcon or objcon_float symbol
+ {
+ int value = (int)pData[1] | ((int)pData[2] << 8) | ((int)pData[3] << 16) | ((int)pData[4] << 24);
+ g_pSymbolEngine->AddSymbol(g_pCompilerData->symbolBackup, (pData[0] == 16) ? type_objcon : type_objcon_float, value);
+#ifdef RPE_DEBUG
+ float fValue = *((float*)(&value));
+ printf("objcon: %s %d %f *\n", g_pCompilerData->symbolBackup, value, fValue);
+#endif
+ pData+=5; // adjust pointer to after value
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
return true;
}
@@ -1117,7 +1182,7 @@ bool CompileVarBlocks()
return true;
}
-bool CompileSubBlocks_Compile(int blockType, int &subCount)
+bool CompileSubBlocks_Compile(int blockType, int &subCount, int &nMethodIndex)
{
bool bEof = false;
g_pElementizer->Reset();
@@ -1310,33 +1375,36 @@ bool CompileSubBlocks_Compile(int blockType, int &subCount)
}
}
- // enter sub offset into index
- *((short*)&(g_pCompilerData->obj[4 + (subCount * 4)])) = (short)g_pCompilerData->obj_ptr;
-
- if (!CompileTopBlock()) // instruction block compiler
+ if (!g_pCompilerData->bFinalCompile || IsMethodUsed(g_pCompilerData->current_filename, nMethodIndex))
{
- return false;
- }
+ // enter sub offset into index
+ *((short*)&(g_pCompilerData->obj[4 + (subCount * 4)])) = (short)g_pCompilerData->obj_ptr;
- g_pCompilerData->inf_start = saved_inf_start;
- g_pCompilerData->inf_finish = g_pElementizer->GetSourcePtr();
- g_pCompilerData->inf_data0 = saved_inf_data0;
- g_pCompilerData->inf_data1 = g_pCompilerData->obj_ptr;
- g_pCompilerData->inf_data2 = saved_inf_data2;
- g_pCompilerData->inf_data3 = saved_inf_data3;
- g_pCompilerData->inf_data4 = (paramCount << 16) | subCount;
- if (blockType == block_pub)
- {
- g_pCompilerData->inf_type = info_pub;
- }
- else
- {
- g_pCompilerData->inf_type = info_pri;
- }
- EnterInfo();
+ if (!CompileTopBlock()) // instruction block compiler
+ {
+ return false;
+ }
- subCount++;
+ g_pCompilerData->inf_start = saved_inf_start;
+ g_pCompilerData->inf_finish = g_pElementizer->GetSourcePtr();
+ g_pCompilerData->inf_data0 = saved_inf_data0;
+ g_pCompilerData->inf_data1 = g_pCompilerData->obj_ptr;
+ g_pCompilerData->inf_data2 = saved_inf_data2;
+ g_pCompilerData->inf_data3 = saved_inf_data3;
+ g_pCompilerData->inf_data4 = (paramCount << 16) | subCount;
+ if (blockType == block_pub)
+ {
+ g_pCompilerData->inf_type = info_pub;
+ }
+ else
+ {
+ g_pCompilerData->inf_type = info_pri;
+ }
+ EnterInfo();
+ subCount++;
+ }
+ nMethodIndex++;
g_pSymbolEngine->Reset(true); // cancel local symbols
}
}
@@ -1352,11 +1420,12 @@ bool CompileSubBlocks_Compile(int blockType, int &subCount)
bool CompileSubBlocks()
{
int subCount = 0;
- if (!CompileSubBlocks_Compile(block_pub, subCount))
+ int nMethodIndex = 0;
+ if (!CompileSubBlocks_Compile(block_pub, subCount, nMethodIndex))
{
return false;
}
- if (!CompileSubBlocks_Compile(block_pri, subCount))
+ if (!CompileSubBlocks_Compile(block_pri, subCount, nMethodIndex))
{
return false;
}
@@ -1485,6 +1554,11 @@ bool CompileFinal()
return false;
}
+ if (!g_pCompilerData->bFinalCompile)
+ {
+ AddObjectPubConList(g_pCompilerData->current_filename, g_pCompilerData->pubcon_list, g_pCompilerData->pubcon_list_size);
+ }
+
// copy pubcon_list into obj (RPE: this could be optimized)
for (int i = 0; i < g_pCompilerData->pubcon_list_size; i++)
{
@@ -1806,7 +1880,7 @@ bool CompileDoc_ScanInterface(bool bPrint, int& nCount)
char currentChar = CompileDoc_ScanSkip(scanPtr);
if (currentChar == '(')
{
- while (1)
+ for (;;)
{
currentChar = g_pCompilerData->source[scanPtr++];
nCount++;
diff --git a/PropellerCompiler/PropellerCompiler.h b/PropellerCompiler/PropellerCompiler.h
index 4abcf39..130a689 100644
--- a/PropellerCompiler/PropellerCompiler.h
+++ b/PropellerCompiler/PropellerCompiler.h
@@ -13,6 +13,8 @@
#ifndef _PROPELLER_COMPILER_H_
#define _PROPELLER_COMPILER_H_
+#include "UnusedMethodUtils.h"
+
//
// OpenSpin code uses _stricmp() which is the VC++ name for the function.
// this needs to be remapped to stricmp or strcasecmp depending on the compiler and OS being compiled on
@@ -34,8 +36,7 @@
#endif
//
-// Everything here needs to stay in the order it is in (for the enums and struct) and remain
-// the same size, in order to be the same as the asm code version and work with Prop Tool / Propellent
+// no longer compatible with Prop Tool / Propellent
//
#define language_version '0'
@@ -47,11 +48,10 @@
#define info_limit 1000
#define distiller_limit 0x4000
#define symbol_limit 256 // was 32
-//#define symbol_table_limit 0x8000
-#define pubcon_list_limit 0x2000
+#define pubcon_list_limit 0x8000
#define block_nest_limit 8
-#define block_stack_limit 256
-#define case_limit 64
+#define block_stack_limit 4096
+#define case_limit 256
#define if_limit 16
#define str_limit 256
#define str_buffer_limit 0x8000
@@ -149,6 +149,11 @@ struct CompilerData
unsigned int vsize; // used to hold last vsize (in case it is greater than 65536)
unsigned int psize; // used to hold last psize (in case it is greater than 65536)
+ char current_filename[256]; // name of object being compiled at the moment
+ bool bFinalCompile; // set to true after unused method scan complete
+
+ int unused_obj_files; // number of unused object files
+ char obj_unused[file_limit*256]; // hold filenames of unused objects
};
// public functions
diff --git a/PropellerCompiler/PropellerCompiler.vcproj b/PropellerCompiler/PropellerCompiler.vcproj
deleted file mode 100644
index 2b0267f..0000000
--- a/PropellerCompiler/PropellerCompiler.vcproj
+++ /dev/null
@@ -1,237 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/PropellerCompiler/PropellerCompiler.vcxproj b/PropellerCompiler/PropellerCompiler.vcxproj
new file mode 100644
index 0000000..56c8814
--- /dev/null
+++ b/PropellerCompiler/PropellerCompiler.vcxproj
@@ -0,0 +1,109 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {DE0E4A74-1C7F-4479-918D-9040BB599F90}
+ PropellerCompiler
+ Win32Proj
+
+
+
+ StaticLibrary
+ v120
+ Unicode
+ true
+
+
+ StaticLibrary
+ v120
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>12.0.30501.0
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+
+
+
+ Disabled
+ WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebug
+
+ false
+
+ Level4
+ EditAndContinue
+
+
+
+
+ MaxSpeed
+ true
+ WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ MultiThreaded
+ true
+
+ false
+
+ Level3
+ ProgramDatabase
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PropellerCompiler/PropellerCompilerInternal.h b/PropellerCompiler/PropellerCompilerInternal.h
index 35235f8..1b40b8d 100644
--- a/PropellerCompiler/PropellerCompilerInternal.h
+++ b/PropellerCompiler/PropellerCompilerInternal.h
@@ -100,7 +100,6 @@ struct CompilerDataInternal : public CompilerData
int bstack_ptr;
int bstack_base[block_nest_limit];
int bstack[block_stack_limit];
-
};
class Elementizer;
diff --git a/PropellerCompiler/UnusedMethodUtils.cpp b/PropellerCompiler/UnusedMethodUtils.cpp
new file mode 100644
index 0000000..519e995
--- /dev/null
+++ b/PropellerCompiler/UnusedMethodUtils.cpp
@@ -0,0 +1,875 @@
+
+///////////////////////////////////////////////////////////////
+// //
+// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
+// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. //
+// See end of file for terms of use. //
+// //
+///////////////////////////////////////////////////////////////
+//
+// UnusedMethodElimination.cpp
+//
+
+#include
+#include
+#include
+
+#include "../PropellerCompiler/PropellerCompiler.h"
+
+//
+// track object names based on "indent" or which child/parent level
+// note: the same name can be in here multiple times at different indent levels
+//
+
+struct ObjectNameEntry
+{
+ char filename[256];
+ int indent;
+};
+
+ObjectNameEntry s_objectNames[128];
+int s_nNumObjectNames = 0;
+
+void AddObjectName(char* pFilename, int indent)
+{
+ strcpy(s_objectNames[s_nNumObjectNames].filename, pFilename);
+
+ // chop off the .spin extension
+ char* pExtension = strstr(s_objectNames[s_nNumObjectNames].filename, ".spin");
+ if (pExtension != 0)
+ {
+ *pExtension = 0;
+ }
+
+ s_objectNames[s_nNumObjectNames].indent = indent-1;
+ s_nNumObjectNames++;
+}
+
+int GetObjectName(int indent, int index)
+{
+ int nCurrIndex = 0;
+ for (int i = 0; i < s_nNumObjectNames; i++)
+ {
+ if (s_objectNames[i].indent == indent)
+ {
+ if (nCurrIndex == index)
+ {
+ return i;
+ }
+ nCurrIndex++;
+ }
+ }
+ return -1;
+}
+
+//
+// track method usage by object
+//
+
+struct IndexEntry
+{
+ short offset; // offset in longs to method (or sub object)
+ short vars; // var offset for objs, locals size for methods
+};
+
+struct CallEntry
+{
+ unsigned int objaddress;
+ unsigned int callOffset;
+ unsigned short objoffset;
+ unsigned char opcode;
+ unsigned char pubnum;
+ unsigned char objnum;
+};
+
+struct MethodUsage
+{
+ int nLength;
+ int nCalled;
+ int nCalls;
+ CallEntry *pCalls;
+ int nCurrCall;
+ int nNewIndex;
+};
+
+struct ObjectEntry
+{
+ int nObjectNameIndex;
+ unsigned char* pObject;
+ int nObjectMethodCount;
+ int nObjectSubObjectCount;
+ int nObjectIndexCount;
+ int nMethodsCalled;
+ int nNewObjectIndex;
+ IndexEntry* pIndexTable;
+ MethodUsage* pMethods;
+};
+
+ObjectEntry s_objects[file_limit];
+int s_nNumObjects;
+
+bool HaveObject(unsigned char* pObject)
+{
+ for (int i = 0; i < s_nNumObjects; i++)
+ {
+ if (s_objects[i].pObject == pObject)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+ObjectEntry* GetObject(unsigned char* pObject)
+{
+ for (int i = 0; i < s_nNumObjects; i++)
+ {
+ if (s_objects[i].pObject == pObject)
+ {
+ return &s_objects[i];
+ }
+ }
+
+ return NULL;
+}
+
+ObjectEntry* GetObjectByName(char* pFilename)
+{
+ for (int i = 0; i < s_nNumObjects; i++)
+ {
+ if (strcmp(s_objectNames[s_objects[i].nObjectNameIndex].filename, pFilename) == 0)
+ {
+ return &s_objects[i];
+ }
+ }
+
+ return NULL;
+}
+
+int AddObject(unsigned char* pObject, int nObjectNameIndex)
+{
+ s_objects[s_nNumObjects].pObject = pObject;
+ s_objects[s_nNumObjects].nObjectNameIndex = nObjectNameIndex;
+ s_objects[s_nNumObjects].nObjectMethodCount = pObject[2]-1;
+ s_objects[s_nNumObjects].nObjectSubObjectCount = pObject[3];
+ s_objects[s_nNumObjects].nObjectIndexCount = s_objects[s_nNumObjects].nObjectMethodCount + s_objects[s_nNumObjects].nObjectSubObjectCount;
+ s_objects[s_nNumObjects].pIndexTable = (IndexEntry *)&(pObject[4]);
+ s_objects[s_nNumObjects].pMethods = new MethodUsage[s_objects[s_nNumObjects].nObjectMethodCount];
+ for (int i = 0; i < s_objects[s_nNumObjects].nObjectMethodCount; i++)
+ {
+ s_objects[s_nNumObjects].pMethods[i].nCalled = 0;
+ s_objects[s_nNumObjects].pMethods[i].nCalls = 0;
+ s_objects[s_nNumObjects].pMethods[i].pCalls = 0;
+ s_objects[s_nNumObjects].pMethods[i].nCurrCall = 0;
+ s_objects[s_nNumObjects].pMethods[i].nNewIndex = 0;
+ s_objects[s_nNumObjects].pMethods[i].nLength = 0;
+ }
+ return s_nNumObjects++;
+}
+
+bool IsObjectUsed(char* pFilename)
+{
+ ObjectEntry* pObject = GetObjectByName(pFilename);
+ if (pObject && pObject->nMethodsCalled > 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool IsMethodUsed(char* pFilename, int nMethod)
+{
+ ObjectEntry* pObject = GetObjectByName(pFilename);
+ if (pObject && pObject->nMethodsCalled > 0 && pObject->pMethods[nMethod].nCalled > 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//
+// store pubcon list data so it can be used in the final compile
+// note: this is needed to allow removing a child object where the parent used only CONs from the child
+//
+
+struct ObjectPubConListEntry
+{
+ char filename[256];
+ unsigned char* pPubConList;
+ int nPubConListSize;
+};
+
+ObjectPubConListEntry s_objectPubConLists[512];
+int s_nNumObjectPubConLists;
+
+ObjectPubConListEntry* GetObjectPubConListEntryByName(char* pFilename)
+{
+ for (int i = 0; i < s_nNumObjectPubConLists; i++)
+ {
+ if (strcmp(s_objectPubConLists[i].filename, pFilename) == 0)
+ {
+ return &s_objectPubConLists[i];
+ }
+ }
+
+ return NULL;
+}
+
+void AddObjectPubConList(char* pFilename, unsigned char* pPubConList, int nPubConListSize)
+{
+ strcpy(s_objectPubConLists[s_nNumObjectPubConLists].filename, pFilename);
+ s_objectPubConLists[s_nNumObjectPubConLists].pPubConList = new unsigned char[nPubConListSize];
+ s_objectPubConLists[s_nNumObjectPubConLists].nPubConListSize = nPubConListSize;
+ memcpy(s_objectPubConLists[s_nNumObjectPubConLists].pPubConList, pPubConList, s_objectPubConLists[s_nNumObjectPubConLists].nPubConListSize);
+ s_nNumObjectPubConLists++;
+}
+
+bool GetObjectPubConList(char* pFilename, unsigned char** ppPubConList, int* pnPubConListSize)
+{
+ ObjectPubConListEntry* pObject = GetObjectPubConListEntryByName(pFilename);
+ if (pObject && pObject->pPubConList != 0 && pObject->nPubConListSize > 0)
+ {
+ *ppPubConList = pObject->pPubConList;
+ *pnPubConListSize = pObject->nPubConListSize;
+ return true;
+ }
+ return false;
+}
+
+void CleanUpUnusedMethodData()
+{
+ for (int i = 0; i < s_nNumObjects; i++)
+ {
+ s_objects[i].pObject = 0;
+ s_objects[i].pIndexTable = 0;
+
+ for (int j = 0; j < s_objects[s_nNumObjects].nObjectMethodCount; j++)
+ {
+ if (s_objects[i].pMethods[j].pCalls)
+ {
+ delete [] s_objects[i].pMethods[j].pCalls;
+ s_objects[i].pMethods[j].pCalls = 0;
+ }
+ }
+ delete [] s_objects[i].pMethods;
+ s_objects[i].pMethods = 0;
+ }
+ s_nNumObjects = 0;
+ s_nNumObjectNames = 0;
+
+ for (int i = 0; i < s_nNumObjectPubConLists; i++)
+ {
+ delete [] s_objectPubConLists[i].pPubConList;
+ s_objectPubConLists[i].pPubConList = 0;
+ }
+ s_nNumObjectPubConLists = 0;
+}
+
+void InitUnusedMethodData()
+{
+ for (int i = 0; i < file_limit; i++)
+ {
+ s_objectPubConLists[i].filename[0] = 0;
+ s_objectPubConLists[i].pPubConList = 0;
+ s_objectPubConLists[i].nPubConListSize = 0;
+ }
+ s_nNumObjectPubConLists = 0;
+ s_nNumObjectNames = 0;
+}
+
+void BuildTables(unsigned char* pObject, int indent, int index)
+{
+#ifdef RPE_DEBUG
+ char *s_indent = " ";
+#define MAX_INDENT 32
+#endif
+
+ if (HaveObject(pObject))
+ {
+#ifdef RPE_DEBUG
+ printf("%sObject Already Added\n", &s_indent[MAX_INDENT-indent]);
+#endif
+ return;
+ }
+ int nNextObjOffset = *((unsigned short *)pObject);
+ int nObjectName = GetObjectName(indent, index);
+ int nObject = AddObject(pObject, nObjectName);
+
+#ifdef RPE_DEBUG
+ printf("%sObject Index Table: %s\n", &s_indent[MAX_INDENT-indent], s_objectNames[s_objects[nObject].nObjectNameIndex].filename);
+#endif
+ for (int i = 0; i < s_objects[nObject].nObjectIndexCount; i++)
+ {
+ if (s_objects[nObject].pIndexTable[i].offset >= nNextObjOffset)
+ {
+#ifdef RPE_DEBUG
+ printf("%s Object Offset: %04d Vars Offset: %d\n", &s_indent[MAX_INDENT-indent], s_objects[nObject].pIndexTable[i].offset, s_objects[nObject].pIndexTable[i].vars);
+#endif
+ BuildTables(&(pObject[s_objects[nObject].pIndexTable[i].offset]), indent + 1, i - s_objects[nObject].nObjectMethodCount);
+ }
+#ifdef RPE_DEBUG
+ else
+ {
+ printf("%s Method Offset: %04d Locals size: %d\n", &s_indent[MAX_INDENT-indent], s_objects[nObject].pIndexTable[i].offset, s_objects[nObject].pIndexTable[i].vars);
+ }
+#endif
+ }
+}
+
+//
+// byte code scanning stuff
+// borrowed from Dave Hein's spinsim code and then modified for my needs (mostly stripped down to just skip intelligently over byte code)
+//
+
+int SkipSignedOffset(unsigned char* pOpcode)
+{
+ return (*pOpcode < 0x80) ? 1 : 2;
+}
+
+int SkipUnsignedOffset(unsigned char* pOpcode)
+{
+ return (*pOpcode & 0x80) ? 2 : 1;
+}
+
+int ScanMathOpcode(unsigned char* pOpcode)
+{
+ bool execflag = false;
+ int opcode = *pOpcode;
+
+ if (opcode < 0xe0)
+ {
+ execflag = true;
+ opcode += 0xe0 - 0x40;
+ }
+
+ // Execute the math op
+ switch (opcode)
+ {
+ case 0xe0: // ror
+ case 0xe1: // rol
+ case 0xe2: // shr
+ case 0xe3: // shl
+ case 0xe4: // min
+ case 0xe5: // max
+ case 0xe6: // neg
+ case 0xe7: // com
+ case 0xe8: // and
+ case 0xe9: // abs
+ case 0xea: // or
+ case 0xeb: // xor
+ case 0xec: // add
+ case 0xed: // sub
+ case 0xee: // sar
+ case 0xef: // rev
+ case 0xf0: // andl
+ case 0xf1: // encode
+ case 0xf4: // mul
+ case 0xf5: // mulh
+ case 0xf2: // orl
+ case 0xf3: // decode
+ case 0xf6: // div
+ case 0xf7: // mod
+ case 0xf8: // sqrt
+ case 0xf9: // cmplt
+ case 0xfa: // cmpgt
+ case 0xfb: // cmpne
+ case 0xfc: // cmpeq
+ case 0xfd: // cmple
+ case 0xfe: // cmpgr
+ case 0xff: // notl
+ break;
+
+ default:
+ break;
+ }
+
+ return (execflag ? 0 : 1);
+}
+
+int ScanExtraOpcode(unsigned char* pOpcode, int opcode)
+{
+ int nOpSize = 0;
+
+ opcode &= 0x7f;
+
+ if (opcode >= 0x40 && opcode < 0x60) // math op
+ {
+ nOpSize += ScanMathOpcode(pOpcode);
+ }
+ else if ((opcode & 0x7e) == 0x00) // store
+ {
+ }
+ else if ((opcode & 0x7a) == 0x02) // repeat, repeats
+ {
+ nOpSize += SkipSignedOffset(pOpcode);
+ }
+ else if ((opcode & 0x78) == 8) // randf, randr
+ {
+ }
+ else if ((opcode & 0x7c) == 0x10) // sexb
+ {
+ }
+ else if ((opcode & 0x7c) == 0x14) // sexw
+ {
+ }
+ else if ((opcode & 0x7c) == 0x18) // postclr
+ {
+ }
+ else if ((opcode & 0x7c) == 0x1c) // postset
+ {
+ }
+ else if ((opcode & 0x78) == 0x20) // preinc
+ {
+ }
+ else if ((opcode & 0x78) == 0x28) // postinc
+ {
+ }
+ else if ((opcode & 0x78) == 0x30) // predec
+ {
+ }
+ else if ((opcode & 0x78) == 0x38) // postdec
+ {
+ }
+ else
+ {
+ printf("NOT IMPLEMENTED\n");
+ }
+
+ return nOpSize;
+}
+
+
+int ScanMemoryOpcode(unsigned char* pOpcode)
+{
+ int opcode = *pOpcode;
+ int memfunc = opcode & 3;
+
+ int nOpSize = 1;
+
+ if (opcode < 0x80) // Compact offset
+ {
+ }
+ else
+ {
+ if ((opcode & 0x0c) >> 2)
+ {
+ nOpSize += SkipUnsignedOffset(&pOpcode[nOpSize]);
+ }
+ }
+
+ if (memfunc == 3) // la
+ {
+ }
+ else if (memfunc == 0) // ld
+ {
+ }
+ else if (memfunc == 1) // st
+ {
+ }
+ else // ex
+ {
+ opcode = pOpcode[nOpSize];
+ nOpSize++;
+
+ nOpSize += ScanExtraOpcode(&pOpcode[nOpSize], opcode);
+ }
+
+ return nOpSize;
+}
+
+int ScanRegisterOpcode(unsigned char* pOpcode, int operand)
+{
+ int opcode;
+ int nOpSize = 0;
+ int memfunc = (operand >> 5) & 3;
+
+ if (memfunc == 1) // store
+ {
+ }
+ else if (memfunc == 0) // load
+ {
+ }
+ else if (memfunc == 2) // execute
+ {
+ opcode = *pOpcode;
+ nOpSize++;
+
+ nOpSize += ScanExtraOpcode(&pOpcode[nOpSize], opcode);
+ }
+ else
+ {
+ printf("Undefined register operation\n");
+ }
+
+ return nOpSize;
+}
+
+int ScanLowerOpcode(unsigned char* pOpcode, MethodUsage* pUsage, ObjectEntry* pObject, unsigned char* pMethodStart)
+{
+ int opcode = *pOpcode;
+ int nOpSize = 1;
+
+ if (opcode <= 3) // ldfrmr, ldfrm, ldfrmar, ldfrma
+ {
+ }
+ else if (opcode == 0x04) // jmp
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode >= 0x05 && opcode <= 0x07) // call, callobj, callobjx
+ {
+ int objnum = 0;
+
+ if (opcode > 0x05)
+ {
+ objnum = pOpcode[nOpSize];
+ nOpSize++;
+ if (opcode == 0x07)
+ {
+ // indexed
+ }
+ }
+
+ int pubnum = pOpcode[nOpSize];
+ nOpSize++;
+
+ // need to update usage here
+ if (pUsage->pCalls == 0)
+ {
+ pUsage->nCalls++;
+ }
+ else
+ {
+ pUsage->pCalls[pUsage->nCurrCall].opcode = (unsigned char)opcode;
+ pUsage->pCalls[pUsage->nCurrCall].pubnum = (unsigned char)pubnum;
+ pUsage->pCalls[pUsage->nCurrCall].callOffset = ((&pOpcode[1]) - pMethodStart);
+
+ if (opcode > 0x05)
+ {
+ pUsage->pCalls[pUsage->nCurrCall].objnum = (unsigned char)objnum;
+ pUsage->pCalls[pUsage->nCurrCall].objoffset = pObject->pIndexTable[objnum-1].offset;
+ pUsage->pCalls[pUsage->nCurrCall].objaddress = (unsigned int)&pObject->pObject[pUsage->pCalls[pUsage->nCurrCall].objoffset];
+#ifdef RPE_DEBUG
+ printf(" callobj %02X:%02X (%08X)\n", pUsage->pCalls[pUsage->nCurrCall].objnum, pUsage->pCalls[pUsage->nCurrCall].pubnum, pUsage->pCalls[pUsage->nCurrCall].objaddress);
+#endif
+ }
+ else
+ {
+ pUsage->pCalls[pUsage->nCurrCall].objnum = 0;
+ pUsage->pCalls[pUsage->nCurrCall].objoffset = 0;
+ pUsage->pCalls[pUsage->nCurrCall].objaddress = (unsigned int)(pObject->pObject);
+#ifdef RPE_DEBUG
+ printf(" call %02X (%08X)\n", pUsage->pCalls[pUsage->nCurrCall].pubnum, pUsage->pCalls[pUsage->nCurrCall].objaddress);
+#endif
+ }
+ pUsage->nCurrCall++;
+ }
+ }
+ else if (opcode == 0x08) // tjz
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode == 0x09) // djnz
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode == 0x0a) // jz
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode == 0x0b) // jnz
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode >= 0x0c && opcode <= 0x15)
+ {
+ if (opcode == 0x0c) // casedone
+ {
+ }
+ else if (opcode == 0x0d) // casevalue
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode == 0x0e) // caserange
+ {
+ nOpSize += SkipSignedOffset(&pOpcode[nOpSize]);
+ }
+ else if (opcode == 0x0f) // lookdone
+ {
+ }
+ else if (opcode == 0x10) // lookupval
+ {
+ }
+ else if (opcode == 0x11) // lookdnval
+ {
+ }
+ else if (opcode == 0x12) // lookuprng
+ {
+ }
+ else if (opcode == 0x13) // lookdnrng
+ {
+ }
+ else if (opcode == 0x14) // pop
+ {
+ }
+ else if (opcode == 0x15) // run
+ {
+ }
+ else
+ {
+ printf("%2.2x - NOT IMPLEMENTED\n", opcode);
+ }
+ }
+ else if (opcode >= 0x16 && opcode <= 0x23)
+ {
+ if (opcode == 0x16) // strsize
+ {
+ }
+ else if (opcode == 0x17) // strcomp
+ {
+ }
+ else if (opcode == 0x18) // bytefill
+ {
+ }
+ else if (opcode == 0x19) // wordfill
+ {
+ }
+ else if (opcode == 0x1a) // longfill
+ {
+ }
+ else if (opcode == 0x1b) // waitpeq
+ {
+ }
+ else if (opcode >= 0x1c && opcode <= 0x1e ) // bytemove, wordmove, longmove
+ {
+ }
+ else if (opcode == 0x1f) // waitpne
+ {
+ }
+ else if (opcode == 0x20) // clkset
+ {
+ }
+ else if (opcode == 0x21) // cogstop
+ {
+ }
+ else if (opcode == 0x22) // lockret
+ {
+ }
+ else if (opcode == 0x23) // waitcnt
+ {
+ }
+ }
+ else if (opcode >= 0x24 && opcode <= 0x2f)
+ {
+ if (opcode >= 0x24 && opcode <= 0x26) // ldregx, stregx, exregx
+ {
+ int operand = ((opcode & 3) << 5);
+ nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand);
+ }
+ else if (opcode == 0x27) // waitvid
+ {
+ }
+ else if (opcode == 0x28 || opcode == 0x2c) // coginitret, coginit
+ {
+ }
+ else if (opcode == 0x29 || opcode == 0x2d) // locknewret, locknew
+ {
+ }
+ else if (opcode == 0x2a || opcode == 0x2b || opcode == 0x2e || opcode == 0x2f) // locksetret, lockclrret, lockset, lockclr
+ {
+ }
+ }
+ else if (opcode >= 0x30 && opcode <= 0x33) // abort, abortval, ret, retval
+ {
+ }
+ else if (opcode >= 0x34 && opcode < 0x3c)
+ {
+ if (opcode == 0x35) // dli0
+ {
+ }
+ else if (opcode == 0x36) // dli1
+ {
+ }
+ else if (opcode == 0x34) // dlim1
+ {
+ }
+ else if (opcode == 0x37) // ldlip
+ {
+ nOpSize++;
+ }
+ else // ldbi, ldwi, ldmi, ldli
+ {
+ while (opcode-- >= 0x38)
+ {
+ nOpSize++;
+ }
+ }
+ }
+ else if (opcode == 0x3d) // ldregbit, stregbit, exregbit
+ {
+ int operand = pOpcode[nOpSize];
+ nOpSize++;
+
+ nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand);
+ }
+ else if (opcode == 0x3e) // ldregbits, stregbits, exregbits
+ {
+ int operand = pOpcode[nOpSize];
+ nOpSize++;
+
+ nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand);
+ }
+ else if (opcode == 0x3f) // ldreg, streg, exreg
+ {
+ int operand = pOpcode[nOpSize];
+ nOpSize++;
+
+ nOpSize += ScanRegisterOpcode(&pOpcode[nOpSize], operand);
+ }
+ else
+ {
+ printf("NOT PROCESSED\n");
+ }
+
+ return nOpSize;
+}
+
+
+int ScanOpcode(unsigned char* pOpcode, MethodUsage* pUsage, ObjectEntry* pObject, unsigned char* pMethodStart)
+{
+ if (*pOpcode < 0x40)
+ {
+ return ScanLowerOpcode(pOpcode, pUsage, pObject, pMethodStart);
+ }
+ else if (*pOpcode < 0xe0)
+ {
+ return ScanMemoryOpcode(pOpcode);
+ }
+ else
+ {
+ return ScanMathOpcode(pOpcode);
+ }
+}
+
+
+void ScanMethod(unsigned char* pMethod, MethodUsage* pUsage, ObjectEntry* pObject)
+{
+#ifdef RPE_DEBUG
+ for (int i = 0; i < pUsage->nLength; i++)
+ {
+ printf("%02x ", pMethod[i]);
+ }
+ printf("\n");
+#endif
+
+ // scan once to count calls
+ int nOffset = 0;
+ while (nOffset < pUsage->nLength)
+ {
+ nOffset += ScanOpcode(&pMethod[nOffset], pUsage, pObject, pMethod);
+ }
+ if (pUsage->nCalls > 0)
+ {
+ // if there were calls then allocate space and scan again to fill in call info
+ pUsage->pCalls = new CallEntry[pUsage->nCalls];
+ nOffset = 0;
+ while (nOffset < pUsage->nLength)
+ {
+ nOffset += ScanOpcode(&pMethod[nOffset], pUsage, pObject, pMethod);
+ }
+ }
+}
+
+void ScanObjectMethods(ObjectEntry* pObjectEntry)
+{
+ for (int i = 0; i < pObjectEntry->nObjectMethodCount; i++)
+ {
+ unsigned char* pMethod = pObjectEntry->pObject + pObjectEntry->pIndexTable[i].offset;
+ int nLength = 0;
+ if (i < pObjectEntry->nObjectMethodCount-1)
+ {
+ nLength = pObjectEntry->pIndexTable[i+1].offset - pObjectEntry->pIndexTable[i].offset;
+ }
+ else
+ {
+ int nNextObjectOffset = *((unsigned short *)(pObjectEntry->pObject));
+ nLength = nNextObjectOffset - pObjectEntry->pIndexTable[i].offset;
+ }
+ pObjectEntry->pMethods[i].nLength = nLength;
+ ScanMethod(pMethod, &(pObjectEntry->pMethods[i]), pObjectEntry);
+ }
+}
+
+void MarkCalls(MethodUsage* pMethod, ObjectEntry* pObject)
+{
+ if (pMethod->nCalled == 0)
+ {
+ pMethod->nCalled = 1;
+ pObject->nMethodsCalled++;
+
+ for (int nCall = 0; nCall < pMethod->nCalls; nCall++)
+ {
+ CallEntry* pCall = &(pMethod->pCalls[nCall]);
+ if ( pCall->opcode == 5 ) // normal call
+ {
+ MarkCalls(&(pObject->pMethods[pCall->pubnum-1]), pObject);
+ }
+ else // obj call
+ {
+ ObjectEntry* pSubObject = GetObject((unsigned char*)(pCall->objaddress));
+ MarkCalls(&(pSubObject->pMethods[pCall->pubnum-1]), pSubObject);
+ }
+ }
+ }
+}
+
+void FindUnusedMethods(CompilerData* pCompilerData)
+{
+ for (int i = 0; i < file_limit; i++)
+ {
+ s_objects[i].pObject = 0;
+ s_objects[i].nObjectMethodCount = 0;
+ s_objects[i].nObjectSubObjectCount = 0;
+ s_objects[i].nObjectIndexCount = 0;
+ s_objects[i].nMethodsCalled = 0;
+ s_objects[i].nNewObjectIndex = 0;
+ s_objects[i].pIndexTable = 0;
+ s_objects[i].pMethods = 0;
+ }
+ s_nNumObjects = 0;
+
+ BuildTables(&(pCompilerData->obj[4]), 0, 0);
+
+ for (int i = 0; i < s_nNumObjects; i++)
+ {
+ ScanObjectMethods(&s_objects[i]);
+ }
+
+ ObjectEntry* pObject = &(s_objects[0]);
+ MethodUsage* pMethod = &(pObject->pMethods[0]);
+ MarkCalls(pMethod, pObject);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// TERMS OF USE: MIT License //
+///////////////////////////////////////////////////////////////////////////////////////////
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this //
+// software and associated documentation files (the "Software"), to deal in the Software //
+// without restriction, including without limitation the rights to use, copy, modify, //
+// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to //
+// permit persons to whom the Software is furnished to do so, subject to the following //
+// conditions: //
+// //
+// The above copyright notice and this permission notice shall be included in all copies //
+// or substantial portions of the Software. //
+// //
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, //
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A //
+// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT //
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION //
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE //
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
+///////////////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/PropellerCompiler/UnusedMethodUtils.h b/PropellerCompiler/UnusedMethodUtils.h
new file mode 100644
index 0000000..f021a6c
--- /dev/null
+++ b/PropellerCompiler/UnusedMethodUtils.h
@@ -0,0 +1,44 @@
+///////////////////////////////////////////////////////////////
+// //
+// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
+// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. //
+// See end of file for terms of use. //
+// //
+///////////////////////////////////////////////////////////////
+//
+// UnusedMethodUtils.h
+//
+
+struct CompilerData;
+
+void AddObjectName(char* pFilename, int indent);
+void FindUnusedMethods(CompilerData* pCompilerData);
+void CleanUpUnusedMethodData();
+void InitUnusedMethodData();
+
+bool IsObjectUsed(char* pFilename);
+bool IsMethodUsed(char* pFilename, int nMethod);
+void AddObjectPubConList(char* pFilename, unsigned char* pPubConList, int nPubConListSize);
+bool GetObjectPubConList(char* pFilename, unsigned char** ppPubConList, int* pnPubConListSize);
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// TERMS OF USE: MIT License //
+///////////////////////////////////////////////////////////////////////////////////////////
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this //
+// software and associated documentation files (the "Software"), to deal in the Software //
+// without restriction, including without limitation the rights to use, copy, modify, //
+// merge, publish, distribute, sublicense, and/or sell copies of the Software, and to //
+// permit persons to whom the Software is furnished to do so, subject to the following //
+// conditions: //
+// //
+// The above copyright notice and this permission notice shall be included in all copies //
+// or substantial portions of the Software. //
+// //
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, //
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A //
+// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT //
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION //
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE //
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //
+///////////////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/PropellerCompiler/Utilities.cpp b/PropellerCompiler/Utilities.cpp
index 93f370c..6304385 100644
--- a/PropellerCompiler/Utilities.cpp
+++ b/PropellerCompiler/Utilities.cpp
@@ -480,7 +480,7 @@ bool GetFilename(int& filenameStart, int& filenameFinish)
filenameStart = g_pCompilerData->source_start;
g_pElementizer->Backup();
- while(1)
+ for (;;)
{
g_pElementizer->GetNext(bEof);
if (g_pElementizer->GetType() != type_con)
@@ -498,7 +498,7 @@ bool GetFilename(int& filenameStart, int& filenameFinish)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_ifc];
- return false;
+ break;
}
// add character
@@ -510,7 +510,7 @@ bool GetFilename(int& filenameStart, int& filenameFinish)
{
g_pCompilerData->error = true;
g_pCompilerData->error_msg = g_pErrorStrings[error_ftl];
- return false;
+ break;
}
if (!g_pElementizer->CheckElement(type_comma))
diff --git a/SpinSource/SpinSource.vcproj b/SpinSource/SpinSource.vcproj
deleted file mode 100644
index cd76e55..0000000
--- a/SpinSource/SpinSource.vcproj
+++ /dev/null
@@ -1,249 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SpinSource/SpinSource.vcxproj b/SpinSource/SpinSource.vcxproj
new file mode 100644
index 0000000..3107024
--- /dev/null
+++ b/SpinSource/SpinSource.vcxproj
@@ -0,0 +1,119 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ openspin
+ {A52778A6-7ABC-4FC5-B238-A6337AB2CC1F}
+ spin
+ Win32Proj
+
+
+
+ Application
+ v120
+ Unicode
+ true
+
+
+ Application
+ v120
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+ <_ProjectFileVersion>12.0.30501.0
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+ false
+
+
+
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ true
+ EnableFastChecks
+ MultiThreadedDebug
+
+ Level4
+ EditAndContinue
+
+
+ true
+ Console
+ MachineX86
+ false
+
+
+
+
+ MaxSpeed
+ true
+ WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ MultiThreaded
+ true
+
+ Level4
+ ProgramDatabase
+
+
+ true
+ Console
+ true
+ true
+ MachineX86
+
+
+
+
+ CompileAsCpp
+
+
+
+
+
+ CompileAsCpp
+
+
+
+
+
+
+
+
+
+
+
+
+ {de0e4a74-1c7f-4479-918d-9040bb599f90}
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SpinSource/flexbuf.c b/SpinSource/flexbuf.cpp
similarity index 100%
rename from SpinSource/flexbuf.c
rename to SpinSource/flexbuf.cpp
diff --git a/SpinSource/openspin.cpp b/SpinSource/openspin.cpp
index 70bc5a2..a7e2c4a 100644
--- a/SpinSource/openspin.cpp
+++ b/SpinSource/openspin.cpp
@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////
// //
// Propeller Spin/PASM Compiler Command Line Tool 'OpenSpin' //
-// (c)2012-2013 Parallax Inc. DBA Parallax Semiconductor. //
+// (c)2012-2015 Parallax Inc. DBA Parallax Semiconductor. //
// Adapted from Jeff Martin's Delphi code by Roy Eltham //
// See end of file for terms of use. //
// //
@@ -21,10 +21,8 @@
#include "preprocess.h"
#define ObjFileStackLimit 16
-
#define ListLimit 2000000
#define DocLimit 2000000
-
#define MAX_FILES 2048 // an object can only reference 32 other objects and only 32 dat files, so the worst case is 32*32*2 files
static struct preprocess s_preprocessor;
@@ -34,6 +32,7 @@ static bool s_bAlternatePreprocessorMode = false;
static int s_nObjStackPtr = 0;
static int s_nFilesAccessed = 0;
static char s_filesAccessed[MAX_FILES][PATH_MAX];
+static bool s_bFinalCompile = false;
static void Banner(void)
{
@@ -63,6 +62,7 @@ usage: openspin\n\
[ -D ] add a define\n\
[ -M ] size of eeprom (up to 16777216 bytes)\n\
[ -s ] dump PUB & CON symbol information for top object\n\
+ [ -u ] enable unused method elimination\n\
spin file to compile\n\
\n");
}
@@ -277,6 +277,18 @@ bool CompileRecursively(char* pFilename, bool bQuiet, bool bFileTreeOutputOnly)
return false;
}
+ if ( !s_pCompilerData->bFinalCompile )
+ {
+ AddObjectName(pFilename, s_nObjStackPtr);
+ }
+
+ strcpy(s_pCompilerData->current_filename, pFilename);
+ char* pExtension = strstr(s_pCompilerData->current_filename, ".spin");
+ if (pExtension != 0)
+ {
+ *pExtension = 0;
+ }
+
// first pass on object
const char* pErrorString = Compile1();
if (pErrorString != 0)
@@ -320,6 +332,12 @@ bool CompileRecursively(char* pFilename, bool bQuiet, bool bFileTreeOutputOnly)
return false;
}
+ strcpy(s_pCompilerData->current_filename, pFilename);
+ char* pExtension = strstr(s_pCompilerData->current_filename, ".spin");
+ if (pExtension != 0)
+ {
+ *pExtension = 0;
+ }
pErrorString = Compile1();
if (pErrorString != 0)
{
@@ -364,6 +382,12 @@ bool CompileRecursively(char* pFilename, bool bQuiet, bool bFileTreeOutputOnly)
}
// second pass of object
+ strcpy(s_pCompilerData->current_filename, pFilename);
+ pExtension = strstr(s_pCompilerData->current_filename, ".spin");
+ if (pExtension != 0)
+ {
+ *pExtension = 0;
+ }
pErrorString = Compile2();
if (pErrorString != 0)
{
@@ -470,7 +494,8 @@ bool ComposeRAM(unsigned char** ppBuffer, int& bufferSize, bool bDATonly, bool b
return true;
}
-void CleanupMemory()
+
+void CleanupMemory(bool bPathsAndUnusedMethodData = true)
{
// cleanup
if ( s_pCompilerData )
@@ -481,7 +506,11 @@ void CleanupMemory()
delete [] s_pCompilerData->source;
}
CleanObjectHeap();
- CleanupPathEntries();
+ if (bPathsAndUnusedMethodData)
+ {
+ CleanupPathEntries();
+ CleanUpUnusedMethodData();
+ }
Cleanup();
}
@@ -504,6 +533,7 @@ int main(int argc, char* argv[])
bool bFileTreeOutputOnly = false;
bool bFileListOutputOnly = false;
bool bDumpSymbols = false;
+ bool bUnusedMethodElimination = false;
// go through the command line arguments, skipping over any -D
for(int i = 1; i < argc; i++)
@@ -644,6 +674,10 @@ int main(int argc, char* argv[])
bDumpSymbols = true;
break;
+ case 'u':
+ bUnusedMethodElimination = true;
+ break;
+
case 'h':
default:
Usage();
@@ -777,7 +811,11 @@ int main(int argc, char* argv[])
printf("%s\n", infile);
}
+ InitUnusedMethodData();
+
+restart_compile:
s_pCompilerData = InitStruct();
+ s_pCompilerData->bFinalCompile = s_bFinalCompile;
s_pCompilerData->list = new char[ListLimit];
s_pCompilerData->list_limit = ListLimit;
@@ -823,6 +861,13 @@ int main(int argc, char* argv[])
if (!bFileTreeOutputOnly && !bFileListOutputOnly && !bDumpSymbols)
{
+ if (!s_bFinalCompile && bUnusedMethodElimination)
+ {
+ FindUnusedMethods(s_pCompilerData);
+ s_bFinalCompile = true;
+ CleanupMemory(false);
+ goto restart_compile;
+ }
unsigned char* pBuffer = NULL;
int bufferSize = 0;
if (ComposeRAM(&pBuffer, bufferSize, bDATonly, bBinary, eeprom_size))
diff --git a/SpinSource/preprocess.c b/SpinSource/preprocess.cpp
similarity index 99%
rename from SpinSource/preprocess.c
rename to SpinSource/preprocess.cpp
index 0860ce4..8ad3ef2 100644
--- a/SpinSource/preprocess.c
+++ b/SpinSource/preprocess.cpp
@@ -824,7 +824,10 @@ do_line(struct preprocess *pp)
// because spin has the # as a valid part of it's syntax and that can be at the start of a line,
// this isn't an error, but instead needs to be parsed like a normal line
// first restore the line
- *(P.save) = (char)(P.c);
+ if (P.save)
+ {
+ *(P.save) = (char)(P.c);
+ }
r = expand_macros(pp, &pp->line, data);
}
}
diff --git a/openspin.sln b/openspin.sln
index 54f7587..5eecc41 100644
--- a/openspin.sln
+++ b/openspin.sln
@@ -1,12 +1,11 @@
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spin", "SpinSource\SpinSource.vcproj", "{A52778A6-7ABC-4FC5-B238-A6337AB2CC1F}"
- ProjectSection(ProjectDependencies) = postProject
- {DE0E4A74-1C7F-4479-918D-9040BB599F90} = {DE0E4A74-1C7F-4479-918D-9040BB599F90}
- EndProjectSection
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openspin", "SpinSource\SpinSource.vcxproj", "{A52778A6-7ABC-4FC5-B238-A6337AB2CC1F}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PropellerCompiler", "PropellerCompiler\PropellerCompiler.vcxproj", "{DE0E4A74-1C7F-4479-918D-9040BB599F90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution