2012-01-23 07:41:05 +00:00
|
|
|
#include <sstream>
|
|
|
|
#include "Parser.h"
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
// Constructors
|
|
|
|
Parser::Parser()
|
|
|
|
{
|
|
|
|
rawBytes = 0;
|
|
|
|
fileLength = 0;
|
|
|
|
filePos = 0;
|
|
|
|
stop = false;
|
2012-01-23 09:59:25 +00:00
|
|
|
stopAddress = 0;
|
2012-01-23 07:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Parser::Parser(std::string filename)
|
|
|
|
{
|
|
|
|
rawBytes = 0;
|
|
|
|
fileLength = 0;
|
|
|
|
filePos = 0;
|
|
|
|
stop = false;
|
|
|
|
|
|
|
|
SetFilename(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deconstructors
|
|
|
|
Parser::~Parser()
|
|
|
|
{
|
|
|
|
// Clear out temporary buffer
|
|
|
|
delete[] rawBytes;
|
|
|
|
|
|
|
|
// Clear out parsed buffer
|
|
|
|
for(unsigned int i = 0; i < parsedBytes.size(); i++)
|
|
|
|
{
|
|
|
|
delete parsedBytes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Getters / Setters
|
|
|
|
string Parser::GetFilename()
|
|
|
|
{
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::SetFilename(std::string value)
|
|
|
|
{
|
|
|
|
filename = value;
|
|
|
|
Read();
|
|
|
|
}
|
|
|
|
|
2012-01-23 09:59:25 +00:00
|
|
|
unsigned int Parser::GetStopAddress()
|
|
|
|
{
|
|
|
|
return stopAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::SetStopAddress(unsigned int value)
|
|
|
|
{
|
|
|
|
stopAddress = value;
|
|
|
|
}
|
|
|
|
|
2012-01-23 07:41:05 +00:00
|
|
|
string Parser::GetParsedAsm()
|
|
|
|
{
|
|
|
|
string tmpStr;
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < parsedString.size(); i++)
|
|
|
|
{
|
|
|
|
tmpStr += parsedString[i] + "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmpStr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// File Operations
|
|
|
|
// Absolutely no error checking at all - likely needs to be done at somepoint
|
|
|
|
void Parser::Read()
|
|
|
|
{
|
|
|
|
// open File
|
|
|
|
fstream tmpFile(filename, ios_base::in | ios_base::binary);
|
|
|
|
|
|
|
|
// Get Length
|
|
|
|
tmpFile.seekg(0, ios::end);
|
|
|
|
fileLength = tmpFile.tellg();
|
|
|
|
tmpFile.seekg(0, ios::beg);
|
|
|
|
|
|
|
|
// Allocate proper memory
|
|
|
|
rawBytes = new char[fileLength];
|
|
|
|
|
|
|
|
// Read filedata
|
|
|
|
tmpFile.read(rawBytes, fileLength);
|
|
|
|
tmpFile.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Code Operations
|
|
|
|
void Parser::Parse(unsigned int offset)
|
|
|
|
{
|
|
|
|
filePos = offset;
|
|
|
|
ParseNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::ParseNext() // Parses the block immidiately following
|
|
|
|
{
|
|
|
|
stringstream tmpStr;
|
|
|
|
unsigned char* rawBytesFixed = (unsigned char*)rawBytes;
|
|
|
|
stop = false;
|
|
|
|
|
|
|
|
// Smart generation
|
|
|
|
bool indent = false;
|
|
|
|
bool firstNonNote = false; // First byte wasn't a note or octacve switch, add ";Setup" comment
|
|
|
|
bool firstNote = false; // First note or octave
|
|
|
|
|
|
|
|
stringstream pos;
|
|
|
|
pos << "; " << hex << uppercase << (unsigned int)filePos;
|
|
|
|
parsedString.push_back(pos.str());
|
|
|
|
|
|
|
|
for(unsigned int i = filePos; (i <= fileLength) && (stop == false); i++)
|
|
|
|
{
|
|
|
|
// There's a way to make this block shorter but for now it does it's job
|
|
|
|
|
|
|
|
// Check to see if it's the correct data type and if so then use it
|
|
|
|
if(tmpCall.IsValid(&rawBytesFixed[i])) // Should have made IsValid static
|
|
|
|
{
|
|
|
|
// Call data type
|
|
|
|
|
|
|
|
// Create data type then move the increment pointer further up as needed
|
|
|
|
parsedBytes.push_back(new Call(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpCall.Arguments(); // should have made Arguments static
|
|
|
|
|
|
|
|
Call* _tmp = (Call*)parsedBytes[parsedBytes.size() - 1];
|
|
|
|
}
|
|
|
|
else if(tmpDuty.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Duty data type
|
|
|
|
parsedBytes.push_back(new Duty(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpDuty.Arguments();
|
|
|
|
}
|
|
|
|
else if(tmpJump.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Jump data type
|
|
|
|
parsedBytes.push_back(new Jump(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpJump.Arguments();
|
|
|
|
|
|
|
|
Jump* _tmp = (Jump*)parsedBytes[parsedBytes.size() - 1];
|
|
|
|
}
|
|
|
|
else if(tmpModulation.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Modulation data type
|
|
|
|
parsedBytes.push_back(new Modulation(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpModulation.Arguments();
|
|
|
|
}
|
|
|
|
else if(tmpNote.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Note data type
|
|
|
|
parsedBytes.push_back(new Note(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpNote.Arguments();
|
|
|
|
}
|
|
|
|
else if(tmpOctave.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Octave data type
|
|
|
|
parsedBytes.push_back(new Octave(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back("\n" + parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpOctave.Arguments();
|
|
|
|
}
|
|
|
|
else if(tmpStop.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Stop data type
|
|
|
|
parsedBytes.push_back(new Stop(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpStop.Arguments();
|
|
|
|
|
|
|
|
stop = true; // Stop all further processing, we've reached the end of the song
|
|
|
|
}
|
|
|
|
else if(tmpTempo.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Tempo data type
|
|
|
|
parsedBytes.push_back(new Tempo(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpTempo.Arguments();
|
|
|
|
}
|
|
|
|
else if(tmpVelocity.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Velocity data type
|
|
|
|
parsedBytes.push_back(new Velocity(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpVelocity.Arguments();
|
|
|
|
}
|
|
|
|
else if(tmpVolume.IsValid(&rawBytesFixed[i]))
|
|
|
|
{
|
|
|
|
// Volume data type
|
|
|
|
parsedBytes.push_back(new Volume(&rawBytesFixed[i]));
|
|
|
|
parsedString.push_back(parsedBytes[parsedBytes.size() - 1]->GenAsm());
|
|
|
|
i += tmpVolume.Arguments();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Unknown code
|
|
|
|
stringstream unkCode;
|
|
|
|
short tmpByte = (short)rawBytesFixed[i];
|
|
|
|
unkCode << "db $" << hex << uppercase << (short)rawBytesFixed[i];
|
|
|
|
parsedString.push_back(unkCode.str());
|
|
|
|
}
|
2012-01-23 09:59:25 +00:00
|
|
|
|
2012-01-23 10:33:56 +00:00
|
|
|
filePos = i;
|
|
|
|
|
2012-01-23 09:59:25 +00:00
|
|
|
// If the stop address parameter is set, break when we get there
|
|
|
|
if( (stopAddress != 0) && (i >= stopAddress) ) break;
|
2012-01-23 07:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now record the postion we left off
|
|
|
|
pos.str("");
|
|
|
|
pos << "; " << hex << uppercase << (unsigned int)filePos;
|
|
|
|
parsedString.push_back(pos.str());
|
|
|
|
|
|
|
|
filePos += 1; // increment 1 for the start of the next possible song
|
|
|
|
}
|