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
|
### 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.
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue