Add #embed preprocessor directive to import binary data

This commit is contained in:
drmortalwombat 2021-10-24 12:34:44 +02:00
parent 42e4f483c1
commit d8ecd34ac6
6 changed files with 163 additions and 10 deletions

View File

@ -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.

View File

@ -558,6 +558,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr
}
else
{
if (!ins->mVolatile)
InsertValue(ins);
}
}
@ -577,6 +578,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr
i++;
}
if (!ins->mVolatile)
InsertValue(ins);
break;
case IC_COPY:

View File

@ -22,9 +22,24 @@ SourcePath::~SourcePath(void)
bool SourceFile::ReadLine(char* line)
{
if (mFile)
{
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)

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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;