Add #embed preprocessor directive to import binary data
This commit is contained in:
parent
42e4f483c1
commit
d8ecd34ac6
22
README.md
22
README.md
|
@ -32,8 +32,6 @@ There are still several open areas, but most targets have been reached. The cur
|
|||
|
||||
### Linker
|
||||
|
||||
* No media file import
|
||||
|
||||
### Standard Libraries
|
||||
|
||||
* No file functions
|
||||
|
@ -93,6 +91,26 @@ Will switch to the lowercase PETSCII font and translate the strings while printi
|
|||
|
||||
Input from the console will also be translated accordingly.
|
||||
|
||||
## Embedding binary data
|
||||
|
||||
The compiler supports the #embed preprocessor directive to import binary data. It converts a section of an external binary file into a sequence of numbers that can be placed into an initializer of an array.
|
||||
|
||||
byte data[] = {
|
||||
|
||||
#embed "data.bin"
|
||||
|
||||
};
|
||||
|
||||
A section of the file can be selected by providing a limit and or an offset into the file before the file name.
|
||||
|
||||
byte data[] = {
|
||||
|
||||
#embed 4096 126 "data.bin"
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
## Inline Assembler
|
||||
|
||||
Inline assembler can be embedded inside of any functions, regardles of their compilation target of byte code or native.
|
||||
|
|
|
@ -558,7 +558,8 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr
|
|||
}
|
||||
else
|
||||
{
|
||||
InsertValue(ins);
|
||||
if (!ins->mVolatile)
|
||||
InsertValue(ins);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,7 +578,8 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr
|
|||
i++;
|
||||
}
|
||||
|
||||
InsertValue(ins);
|
||||
if (!ins->mVolatile)
|
||||
InsertValue(ins);
|
||||
break;
|
||||
case IC_COPY:
|
||||
i = 0;
|
||||
|
|
|
@ -23,8 +23,23 @@ bool SourceFile::ReadLine(char* line)
|
|||
{
|
||||
if (mFile)
|
||||
{
|
||||
if (fgets(line, 1024, mFile))
|
||||
return true;
|
||||
if (mBinary)
|
||||
{
|
||||
if (mLimit)
|
||||
mLimit--;
|
||||
|
||||
int c = fgetc(mFile);
|
||||
if (c >= 0)
|
||||
{
|
||||
sprintf_s(line, 1024, "0x%02x, ", c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fgets(line, 1024, mFile))
|
||||
return true;
|
||||
}
|
||||
|
||||
fclose(mFile);
|
||||
mFile = nullptr;
|
||||
|
@ -33,6 +48,13 @@ bool SourceFile::ReadLine(char* line)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SourceFile::Limit(int skip, int limit)
|
||||
{
|
||||
mLimit = limit;
|
||||
if (mFile)
|
||||
fseek(mFile, skip, SEEK_SET);
|
||||
}
|
||||
|
||||
SourceFile::SourceFile(void)
|
||||
: mFile(nullptr), mFileName{ 0 }, mStack(nullptr)
|
||||
{
|
||||
|
@ -48,7 +70,7 @@ SourceFile::~SourceFile(void)
|
|||
}
|
||||
}
|
||||
|
||||
bool SourceFile::Open(const char* name, const char* path)
|
||||
bool SourceFile::Open(const char* name, const char* path, bool binary)
|
||||
{
|
||||
char fname[220];
|
||||
|
||||
|
@ -66,7 +88,7 @@ bool SourceFile::Open(const char* name, const char* path)
|
|||
|
||||
strcat_s(fname + n, sizeof(fname) - n, name);
|
||||
|
||||
if (!fopen_s(&mFile, fname, "r"))
|
||||
if (!fopen_s(&mFile, fname, binary ? "rb" : "r"))
|
||||
{
|
||||
_fullpath(mFileName, fname, sizeof(mFileName));
|
||||
char* p = mFileName;
|
||||
|
@ -76,6 +98,9 @@ bool SourceFile::Open(const char* name, const char* path)
|
|||
*p = '/';
|
||||
p++;
|
||||
}
|
||||
mBinary = binary;
|
||||
mLimit = 0x10000;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -143,6 +168,67 @@ bool Preprocessor::NextLine(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Preprocessor::EmbedData(const char* reason, const char* name, bool local, int skip, int limit)
|
||||
{
|
||||
if (strlen(name) > 200)
|
||||
{
|
||||
mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Binary file path exceeds max path length");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSource)
|
||||
mSource->mLocation = mLocation;
|
||||
|
||||
SourceFile* source = new SourceFile();
|
||||
|
||||
bool ok = false;
|
||||
|
||||
if (source->Open(name, "", true))
|
||||
ok = true;
|
||||
|
||||
if (!ok && local && mSource)
|
||||
{
|
||||
char lpath[220];
|
||||
strcpy_s(lpath, mSource->mFileName);
|
||||
int i = strlen(lpath);
|
||||
while (i > 0 && lpath[i - 1] != '/')
|
||||
i--;
|
||||
lpath[i] = 0;
|
||||
|
||||
if (source->Open(name, lpath, true))
|
||||
ok = true;
|
||||
}
|
||||
|
||||
SourcePath* p = mPaths;
|
||||
while (!ok && p)
|
||||
{
|
||||
if (source->Open(name, p->mPathName, true))
|
||||
ok = true;
|
||||
else
|
||||
p = p->mNext;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
printf("%s \"%s\"\n", reason, source->mFileName);
|
||||
|
||||
source->Limit(skip, limit);
|
||||
|
||||
source->mUp = mSource;
|
||||
mSource = source;
|
||||
mLocation.mFileName = mSource->mFileName;
|
||||
mLocation.mLine = 0;
|
||||
mLine[0] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete source;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Preprocessor::OpenSource(const char * reason, const char* name, bool local)
|
||||
{
|
||||
if (strlen(name) > 200)
|
||||
|
|
|
@ -21,15 +21,19 @@ public:
|
|||
SourceFile * mUp, * mNext;
|
||||
Location mLocation;
|
||||
SourceStack * mStack;
|
||||
bool mBinary;
|
||||
int mLimit;
|
||||
|
||||
bool ReadLine(char* line);
|
||||
|
||||
SourceFile(void);
|
||||
~SourceFile(void);
|
||||
|
||||
bool Open(const char* name, const char * path);
|
||||
bool Open(const char* name, const char * path, bool binary = false);
|
||||
void Close(void);
|
||||
|
||||
void Limit(int skip, int limit);
|
||||
|
||||
bool PushSource(void);
|
||||
bool PopSource(void);
|
||||
bool DropSource(void);
|
||||
|
@ -70,6 +74,8 @@ public:
|
|||
bool PopSource(void);
|
||||
bool DropSource(void);
|
||||
|
||||
bool EmbedData(const char* reason, const char* name, bool local, int skip, int limit);
|
||||
|
||||
Preprocessor(Errors * errors);
|
||||
~Preprocessor(void);
|
||||
};
|
||||
|
|
|
@ -118,6 +118,8 @@ const char* TokenNames[] = {
|
|||
"':'",
|
||||
"'?'",
|
||||
|
||||
"embedded",
|
||||
|
||||
"'#define'",
|
||||
"'#include'",
|
||||
"'#if'",
|
||||
|
@ -130,7 +132,8 @@ const char* TokenNames[] = {
|
|||
|
||||
"'#assign'",
|
||||
"'#repeat'",
|
||||
"'#until'"
|
||||
"'#until'",
|
||||
"'#embed'"
|
||||
};
|
||||
|
||||
|
||||
|
@ -590,6 +593,36 @@ void Scanner::NextToken(void)
|
|||
}
|
||||
mPreprocessorMode = false;
|
||||
}
|
||||
else if (mToken == TK_PREP_EMBED)
|
||||
{
|
||||
int limit = 65536, skip = 0;
|
||||
|
||||
NextRawToken();
|
||||
if (mToken == TK_INTEGER)
|
||||
{
|
||||
limit = mTokenInteger;
|
||||
NextRawToken();
|
||||
|
||||
if (mToken == TK_INTEGER)
|
||||
{
|
||||
skip = mTokenInteger;
|
||||
NextRawToken();
|
||||
}
|
||||
}
|
||||
|
||||
if (mToken == TK_STRING)
|
||||
{
|
||||
if (!mPreprocessor->EmbedData("Embedding", mTokenString, true, skip, limit))
|
||||
mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString);
|
||||
}
|
||||
else if (mToken == TK_LESS_THAN)
|
||||
{
|
||||
mOffset--;
|
||||
StringToken('>');
|
||||
if (!mPreprocessor->EmbedData("Embedding", mTokenString, false, skip, limit))
|
||||
mErrors->Error(mLocation, EERR_FILE_NOT_FOUND, "Could not open source file", mTokenString);
|
||||
}
|
||||
}
|
||||
else if (mToken == TK_IDENT)
|
||||
{
|
||||
Macro* def = nullptr;
|
||||
|
@ -1014,6 +1047,8 @@ void Scanner::NextRawToken(void)
|
|||
mToken = TK_PREP_REPEAT;
|
||||
else if (!strcmp(tkprep, "until"))
|
||||
mToken = TK_PREP_UNTIL;
|
||||
else if (!strcmp(tkprep, "embed"))
|
||||
mToken = TK_PREP_EMBED;
|
||||
else
|
||||
mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep);
|
||||
}
|
||||
|
|
|
@ -117,6 +117,8 @@ enum Token
|
|||
TK_COLON,
|
||||
TK_QUESTIONMARK,
|
||||
|
||||
TK_EMBEDDED,
|
||||
|
||||
TK_PREP_DEFINE,
|
||||
TK_PREP_INCLUDE,
|
||||
TK_PREP_IF,
|
||||
|
@ -130,6 +132,7 @@ enum Token
|
|||
TK_PREP_ASSIGN,
|
||||
TK_PREP_REPEAT,
|
||||
TK_PREP_UNTIL,
|
||||
TK_PREP_EMBED,
|
||||
|
||||
NUM_TOKENS
|
||||
};
|
||||
|
@ -193,6 +196,9 @@ public:
|
|||
const Ident * mTokenIdent;
|
||||
char mTokenString[1024], mTokenChar;
|
||||
|
||||
uint8 * mTokenEmbed;
|
||||
int mTokenEmbedSize;
|
||||
|
||||
Token mToken;
|
||||
double mTokenNumber;
|
||||
unsigned int mTokenInteger;
|
||||
|
|
Loading…
Reference in New Issue