From d8ecd34ac6045491d0e07a78e6407bd65b55bd8e Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Sun, 24 Oct 2021 12:34:44 +0200 Subject: [PATCH] Add #embed preprocessor directive to import binary data --- README.md | 22 +++++++++- oscar64/InterCode.cpp | 6 ++- oscar64/Preprocessor.cpp | 94 ++++++++++++++++++++++++++++++++++++++-- oscar64/Preprocessor.h | 8 +++- oscar64/Scanner.cpp | 37 +++++++++++++++- oscar64/Scanner.h | 6 +++ 6 files changed, 163 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 11d9187..4ba56b3 100644 --- a/README.md +++ b/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. diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 2b2eeaa..fc793d1 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -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; diff --git a/oscar64/Preprocessor.cpp b/oscar64/Preprocessor.cpp index ac11d78..3c57f6a 100644 --- a/oscar64/Preprocessor.cpp +++ b/oscar64/Preprocessor.cpp @@ -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) diff --git a/oscar64/Preprocessor.h b/oscar64/Preprocessor.h index 522d3af..711fcd6 100644 --- a/oscar64/Preprocessor.h +++ b/oscar64/Preprocessor.h @@ -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); }; diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index aa9ad02..6904027 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -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); } diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index 89b9621..d071a00 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -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;