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 ### Linker
* No media file import
### Standard Libraries ### Standard Libraries
* No file functions * 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. 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
Inline assembler can be embedded inside of any functions, regardles of their compilation target of byte code or native. 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 else
{ {
if (!ins->mVolatile)
InsertValue(ins); InsertValue(ins);
} }
} }
@ -577,6 +578,7 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr
i++; i++;
} }
if (!ins->mVolatile)
InsertValue(ins); InsertValue(ins);
break; break;
case IC_COPY: case IC_COPY:

View File

@ -22,9 +22,24 @@ SourcePath::~SourcePath(void)
bool SourceFile::ReadLine(char* line) bool SourceFile::ReadLine(char* line)
{ {
if (mFile) 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)) if (fgets(line, 1024, mFile))
return true; return true;
}
fclose(mFile); fclose(mFile);
mFile = nullptr; mFile = nullptr;
@ -33,6 +48,13 @@ bool SourceFile::ReadLine(char* line)
return false; return false;
} }
void SourceFile::Limit(int skip, int limit)
{
mLimit = limit;
if (mFile)
fseek(mFile, skip, SEEK_SET);
}
SourceFile::SourceFile(void) SourceFile::SourceFile(void)
: mFile(nullptr), mFileName{ 0 }, mStack(nullptr) : 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]; char fname[220];
@ -66,7 +88,7 @@ bool SourceFile::Open(const char* name, const char* path)
strcat_s(fname + n, sizeof(fname) - n, name); 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)); _fullpath(mFileName, fname, sizeof(mFileName));
char* p = mFileName; char* p = mFileName;
@ -76,6 +98,9 @@ bool SourceFile::Open(const char* name, const char* path)
*p = '/'; *p = '/';
p++; p++;
} }
mBinary = binary;
mLimit = 0x10000;
return true; return true;
} }
@ -143,6 +168,67 @@ bool Preprocessor::NextLine(void)
return false; 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) bool Preprocessor::OpenSource(const char * reason, const char* name, bool local)
{ {
if (strlen(name) > 200) if (strlen(name) > 200)

View File

@ -21,15 +21,19 @@ public:
SourceFile * mUp, * mNext; SourceFile * mUp, * mNext;
Location mLocation; Location mLocation;
SourceStack * mStack; SourceStack * mStack;
bool mBinary;
int mLimit;
bool ReadLine(char* line); bool ReadLine(char* line);
SourceFile(void); SourceFile(void);
~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 Close(void);
void Limit(int skip, int limit);
bool PushSource(void); bool PushSource(void);
bool PopSource(void); bool PopSource(void);
bool DropSource(void); bool DropSource(void);
@ -70,6 +74,8 @@ public:
bool PopSource(void); bool PopSource(void);
bool DropSource(void); bool DropSource(void);
bool EmbedData(const char* reason, const char* name, bool local, int skip, int limit);
Preprocessor(Errors * errors); Preprocessor(Errors * errors);
~Preprocessor(void); ~Preprocessor(void);
}; };

View File

@ -118,6 +118,8 @@ const char* TokenNames[] = {
"':'", "':'",
"'?'", "'?'",
"embedded",
"'#define'", "'#define'",
"'#include'", "'#include'",
"'#if'", "'#if'",
@ -130,7 +132,8 @@ const char* TokenNames[] = {
"'#assign'", "'#assign'",
"'#repeat'", "'#repeat'",
"'#until'" "'#until'",
"'#embed'"
}; };
@ -590,6 +593,36 @@ void Scanner::NextToken(void)
} }
mPreprocessorMode = false; 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) else if (mToken == TK_IDENT)
{ {
Macro* def = nullptr; Macro* def = nullptr;
@ -1014,6 +1047,8 @@ void Scanner::NextRawToken(void)
mToken = TK_PREP_REPEAT; mToken = TK_PREP_REPEAT;
else if (!strcmp(tkprep, "until")) else if (!strcmp(tkprep, "until"))
mToken = TK_PREP_UNTIL; mToken = TK_PREP_UNTIL;
else if (!strcmp(tkprep, "embed"))
mToken = TK_PREP_EMBED;
else else
mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep); mErrors->Error(mLocation, EERR_INVALID_PREPROCESSOR, "Invalid preprocessor command", tkprep);
} }

View File

@ -117,6 +117,8 @@ enum Token
TK_COLON, TK_COLON,
TK_QUESTIONMARK, TK_QUESTIONMARK,
TK_EMBEDDED,
TK_PREP_DEFINE, TK_PREP_DEFINE,
TK_PREP_INCLUDE, TK_PREP_INCLUDE,
TK_PREP_IF, TK_PREP_IF,
@ -130,6 +132,7 @@ enum Token
TK_PREP_ASSIGN, TK_PREP_ASSIGN,
TK_PREP_REPEAT, TK_PREP_REPEAT,
TK_PREP_UNTIL, TK_PREP_UNTIL,
TK_PREP_EMBED,
NUM_TOKENS NUM_TOKENS
}; };
@ -193,6 +196,9 @@ public:
const Ident * mTokenIdent; const Ident * mTokenIdent;
char mTokenString[1024], mTokenChar; char mTokenString[1024], mTokenChar;
uint8 * mTokenEmbed;
int mTokenEmbedSize;
Token mToken; Token mToken;
double mTokenNumber; double mTokenNumber;
unsigned int mTokenInteger; unsigned int mTokenInteger;