added pragma support to build_segment tool

This commit is contained in:
FeralChild64 committed 2020-01-15 17:54:29 +01:00
1 parent 41c94e0577
commit 73f05a13c8
5 files changed
+131 -24

No files matched your search

+97 -6
View File
@@ -79,9 +79,14 @@ class SourceFile
public:
SourceFile(const std::string &fileName, const std::string &dirName);
void preprocess();
bool preprocessLine(const std::string &line);
bool nameMatch(const std::string &token, const std::string &name);
std::string fileName;
std::string dirName;
bool ignore;
bool floating;
std::vector<char> content;
@@ -120,7 +125,7 @@ public:
class Solver
{
public:
Solver(BinningProblem &problem) : problem(problem), logOutput(logFile, std::cout) {}
explicit Solver(BinningProblem &problem) : problem(problem), logOutput(logFile, std::cout) {}
void run();
@@ -164,7 +169,7 @@ void parseCommandLine(int argc, char **argv)
case 'd': CMD_outDir = optarg; break;
case 's': CMD_segName = optarg; break;
case 'i': CMD_segInfo = optarg; break;
case 'r': CMD_romLayout = optarg; break;
case 'r': CMD_romLayout = optarg; break;
case 'l': CMD_loAddress = strtol(optarg, nullptr ,16); break;
case 'h': CMD_hiAddress = strtol(optarg, nullptr ,16); break;
default: printUsage(); ERROR();
@@ -196,7 +201,7 @@ void readSourceFiles()
// This is a regular file
char *tmp1 = strdup(objName.c_str());
char *tmp2 = strdup(objName.c_str());
char *tmp2 = strdup(objName.c_str());
std::string dirName = dirname(tmp1);
std::string fileName = basename(tmp2);
@@ -235,6 +240,11 @@ void readSourceFiles()
closedir(dirHandle);
}
// Filter-out files marked as ignored
GLOBAL_sourceFiles.erase(std::remove_if(GLOBAL_sourceFiles.begin(), GLOBAL_sourceFiles.end(),
[](const SourceFile &sourceFile) -> bool { return sourceFile.ignore; }), GLOBAL_sourceFiles.end());
if (GLOBAL_sourceFiles.empty()) ERROR("no source files found");
// Sort the file list by name, to provide deterministic results
@@ -485,7 +495,7 @@ void compileSegment()
", outBin=\"" << CMD_outFile << "\", fill]" <<
"\n";
outFile << "#define SEGMENT_" << CMD_segName << "\n";
outFile << "#define ROM_LAYOUT_" << CMD_romLayout << "\n";
outFile << "#define ROM_LAYOUT_" << CMD_romLayout << "\n";
outFile << ".namespace " << CMD_segName << " {" << "\n\n";
// Write files which only contain definitions (no routines)
@@ -557,6 +567,7 @@ int main(int argc, char **argv)
SourceFile::SourceFile(const std::string &fileName, const std::string &dirName) :
fileName(fileName),
dirName(dirName),
ignore(false),
floating(false),
startAddr(-1),
codeLength(-1),
@@ -607,6 +618,10 @@ SourceFile::SourceFile(const std::string &fileName, const std::string &dirName)
startAddr = strtol(fileName.substr(0, 4).c_str(), nullptr ,16);
}
// Preprocess the file (apply settings from the content)
preprocess();
// Generate KickAss compatible label from the file name
label = fileName.substr(0, fileName.length() - 2);
@@ -615,6 +630,82 @@ SourceFile::SourceFile(const std::string &fileName, const std::string &dirName)
std::replace(label.begin(), label.end(), ',', '_');
}
void SourceFile::preprocess()
{
std::string contentStr(content.begin(), content.end());
std::istringstream stream(contentStr);
std::string line;
while (std::getline(stream, line))
{
if (line.empty()) continue;
std::replace(std::begin(line), std::end(line), '\t', ' ');
if (!preprocessLine(line)) break;
}
}
bool SourceFile::preprocessLine(const std::string &line)
{
// Split the line into tokens
std::list<std::string> tokens;
std::istringstream stream(line);
std::string token;
while(std::getline(stream, token, ' '))
{
if (token.empty()) continue;
tokens.push_back(token);
}
if (tokens.empty()) return true;
// Now preprocess line using the token list
auto iter = tokens.begin();
// Injest the comment token
if ((iter++)->compare("//") != 0 || iter == tokens.end()) return true;
// Check if supported directive
if ((iter++)->compare("#LAYOUT#") != 0) return true;
// Check if segment name and rom layout match
if (iter == tokens.end()) ERROR("syntax error, missing segment name in '#LAYOUT#'");
if (!nameMatch(*(iter++), CMD_segName)) return true;
if (iter == tokens.end()) ERROR("syntax error, missing rom layout in '#LAYOUT#'");
if (!nameMatch(*(iter++), CMD_romLayout)) return true;
// Retrieve and apply action
if (iter == tokens.end()) ERROR("syntax error, missing action in '#LAYOUT#'");
if (iter->compare("#IGNORE") == 0)
{
ignore = true;
}
else if (iter->compare("#TAKE-FLOAT") == 0)
{
floating = true;
}
else if (iter->compare("#TAKE") != 0)
{
ERROR("syntax error, unsupported action in '#LAYOUT#'");
}
// Tell the caller to finish processing the file
return false;
}
bool SourceFile::nameMatch(const std::string &token, const std::string &name)
{
return (token.compare("*") == 0) || (token.compare(name) == 0);
}
//
// Class 'BinningProblem'
//
@@ -630,7 +721,7 @@ BinningProblem::BinningProblem(int loAddress, int hiAddress)
gaps[loAddress] = hiAddress - loAddress + 1;
// Initial value of statistics
// Initial value of statistics
statSize = gaps[loAddress];
statFree = gaps[loAddress];
@@ -672,7 +763,7 @@ void BinningProblem::addToProblem(SourceFile *routine)
// Put the routine into the gap, possibly removing it or splitting into two
fixedRoutines[routine->startAddr] = routine;
statFree -= routine->codeLength;
statFree -= routine->codeLength;
// Calculate possible new gap after the routine