From b56144e2b94efdc988f57f62b424db063ce0386a Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Wed, 25 Oct 2017 08:27:51 +0300 Subject: [PATCH] implemented last missing ":=" syntax; changed syntax for arrays of vectors: `{ {x, y}, {x, y} }` --- src/felib/fesave.cpp | 191 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/felib/fesave.h | 38 ++++++++-- 2 files changed, 217 insertions(+), 12 deletions(-) diff --git a/src/felib/fesave.cpp b/src/felib/fesave.cpp index 8123c30..dc5cc41 100644 --- a/src/felib/fesave.cpp +++ b/src/felib/fesave.cpp @@ -129,6 +129,43 @@ festring inputfile::GetMyDir (void) { //////////////////////////////////////////////////////////////////////////////// +struct InputFileSaved { + friend inputfile; + +private: + inputfile *ifile; + int mCharBuf[4]; + int mCharBufPos; + int mCurrentLine; + int mTokenLine; + sLong mCurPos; + +private: + InputFileSaved (inputfile *aifile) { + ifile = aifile; + if (aifile) { + memcpy(mCharBuf, aifile->mCharBuf, sizeof(mCharBuf)); + mCharBufPos = aifile->mCharBufPos; + mCurrentLine = aifile->mCurrentLine; + mTokenLine = aifile->mTokenLine; + mCurPos = aifile->TellPos(); + } + } + +public: + ~InputFileSaved () { + if (ifile) { + memcpy(ifile->mCharBuf, mCharBuf, sizeof(ifile->mCharBuf)); + ifile->mCharBufPos = mCharBufPos; + ifile->mCurrentLine = mCurrentLine; + ifile->mTokenLine = mTokenLine; + ifile->SeekPosBegin(mCurPos); + } + } +}; + + +//////////////////////////////////////////////////////////////////////////////// inputfile::inputfile (cfestring &FileName, const valuemap *ValueMap, truth AbortOnErr) : #ifdef USE_ZLIB Buffer(gzopen(FileName.CStr(), "rb")), @@ -173,7 +210,6 @@ int inputfile::Get () { return mCharBuf[--mCharBufPos]; } else if (Buffer) { int ch = Xgetc(Buffer); - // if (ch == '\n') ++mCurrentLine; return (ch < 0 ? EOF : ch); } else { @@ -196,6 +232,116 @@ truth inputfile::Eof () { } +void inputfile::skipBlanks () { + for (;;) { + int ch = Get(); + if (ch == EOF) return; + // comment? + if (ch == '/') { + if (Eof()) { Unget(ch); return; } + ch = Get(); + // multiline comment? (possibly nested) + if (ch == '*') { + int prevch = ' ', level = 1; + for (;;) { + if (Eof()) return; + ch = Get(); + if (prevch == '*' && ch == '/') { + if (--level == 0) break; + prevch = ' '; + } else if (prevch == '/' && ch == '*') { + ++level; + prevch = ' '; + } else { + prevch = ch; + } + } + continue; + } + // one-line comment? + if (ch == '/') { + while (!Eof()) { ch = Get(); if (ch == '\n') break; } + continue; + } + Unget('/'); + return; + } + // space? + if (ch >= 0 && ch <= ' ') continue; + // not a space + Unget(ch); + return; + } +} + + +#define StackDepth (256) +int inputfile::countArrayItems (char echar) { + auto savedPos = InputFileSaved(this); + char stack[StackDepth]; // end chars + int sp = 0; + stack[0] = echar; + skipBlanks(); + int ch = Get(); + if (ch == EOF) return -1; // oops + if (ch == ',' || ch == ';') return -1; + //fprintf(stderr, "COUNT: ch='%c'\n", ch); + if (ch == echar) return 0; + Unget(ch); + int count = 1; + while (sp >= 0) { + skipBlanks(); + ch = Get(); + if (ch == EOF) return -1; // oops + // string? + if (ch == '"' || ch == '\'') { + echar = ch; + while (ch != EOF) { + ch = Get(); + if (ch == '\\') { + ch = Get(); + if (ch == EOF) return -1; // oops + } else if (ch == echar) { + break; + } + } + continue; + } + if (sp == 0 && (ch == ',' || ch == ';')) { + skipBlanks(); + ch = Get(); + if (ch == EOF) return -1; + if (ch == ',' || ch == ';') return -1; + //fprintf(stderr, " oldcount=%d; ch='%c'; sp=%d\n", count, ch, sp); + if (sp == 0 && ch == stack[0]) {} else ++count; + //fprintf(stderr, " newcount=%d; ch='%c'; sp=%d\n", count, ch, sp); + //if (ch != ')' && ch != ']' && ch != '}') ++count; + } + // endchar? + if (ch == stack[sp]) { + //fprintf(stderr, " *close; ch='%c'; sp=%d\n", ch, sp); + --sp; + continue; + } + // check for openings + switch (ch) { + case '(': echar = ')'; break; + case '[': echar = ']'; break; + case '{': echar = '}'; break; + case ')': case ']': case '}': return -1; // oops + default: echar = 0; break; + } + if (echar) { + if (sp >= StackDepth-1) return -1; // oops + //fprintf(stderr, " *open; ch='%c'; echar='%c'; sp=%d\n", ch, echar, sp); + stack[++sp] = echar; + } + } + return count; +} +#undef StackDepth + + void inputfile::Read (char *Offset, sLong Size) { if (!Buffer) ABORT("Trying to read from unopened file '%s'!", FileName.CStr()); #ifdef USE_ZLIB @@ -224,17 +370,14 @@ void inputfile::SeekPosEnd (sLong Offset) { int opos; char *buffer, buf[512]; int bufsize; - // for (bufsize = 256*1024; bufsize > (int)sizeof(buf); bufsize /= 2) { if ((buffer = (char *)malloc(bufsize)) != NULL) break; } if (buffer == NULL) { buffer = buf; bufsize = sizeof(buf); } - // //fprintf(stderr, "determining file size...\n"); mFileSize = opos = gztell(Buffer); for (;;) { int len = gzread(Buffer, buffer, bufsize); - // if (len < 0) { mFileSize = -1; break; } // error mFileSize += len; if (len < bufsize) break; // eof reached @@ -242,9 +385,7 @@ void inputfile::SeekPosEnd (sLong Offset) { if (buffer != buf) free(buffer); //fprintf(stderr, "file size: %d\n", ctx->filesize); } - // if (mFileSize < 0) ABORT("File '%s': seek error!", FileName.CStr()); - // if (gzseek(Buffer, mFileSize+Offset, SEEK_SET) < 0) ABORT("File '%s': seek error!", FileName.CStr()); } @@ -716,8 +857,10 @@ festring inputfile::ReadNumberIntr (int CallLevel, sLong *num, truth *isString, if (num) *num = 0; if (wasCloseBrc) *wasCloseBrc = false; mTokenLine = mCurrentLine; + //fprintf(stderr, ">>> ReadNumberIntr()\n"); for (;;) { ReadWord(Word); + //fprintf(stderr, " ReadNumberIntr: word='%s'\n", Word.CStr()); // specials? if (Word == "@") { // variable @@ -767,10 +910,18 @@ festring inputfile::ReadNumberIntr (int CallLevel, sLong *num, truth *isString, if (mCollectingNumStr) mNumStr << Word; Value = atoi(Word.CStr()); NumberCorrect = true; + // HACK: autoinsert terminator + skipBlanks(); + int ch = Get(); + if (ch != EOF) { + Unget(ch); + if (ch == '}') Unget(';'); + } continue; } // delimiter/math? if (Word.GetSize() == 1) { + //fprintf(stderr, " ReadNumberIntr: First='%c'\n", First); if (First == ';' || First == ',' || First == ':' || (wasCloseBrc && First == '}')) { if (First == '}' && wasCloseBrc) *wasCloseBrc = true; if (CallLevel != HIGHEST || PreserveTerminator) Unget(First); @@ -1018,19 +1169,47 @@ festring inputfile::ReadStringOrNumberKeepStr (sLong *num, truth *isString, trut v2 inputfile::ReadVector2d () { + skipBlanks(); + int ch = Get(); + if (ch == '{') ch = '}'; else { Unget(ch); ch = 0; } + v2 Vector; Vector.X = ReadNumber(); Vector.Y = ReadNumber(); + + if (ch) { + skipBlanks(); + if (Get() != ch) ABORT("Vector syntax error: \"%c\" expected in file %s, line %d!", ch, GetFileName().CStr(), TokenLine()); + skipBlanks(); + ch = Get(); + if (ch == '}') Unget(ch); + else if (ch != ';' && ch != ',') ABORT("Vector syntax error: terminator expected in file %s, line %d!", GetFileName().CStr(), TokenLine()); + } + return Vector; } rect inputfile::ReadRect () { + skipBlanks(); + int ch = Get(); + if (ch == '{') ch = '}'; else { Unget(ch); ch = 0; } + rect Rect; Rect.X1 = ReadNumber(); Rect.Y1 = ReadNumber(); Rect.X2 = ReadNumber(); Rect.Y2 = ReadNumber(); + + if (ch) { + skipBlanks(); + if (Get() != ch) ABORT("Vector syntax error: \"%c\" expected in file %s, line %d!", ch, GetFileName().CStr(), TokenLine()); + skipBlanks(); + ch = Get(); + if (ch == '}') Unget(ch); + else if (ch != ';' && ch != ',') ABORT("Vector syntax error: terminator expected in file %s, line %d!", GetFileName().CStr(), TokenLine()); + } + return Rect; } diff --git a/src/felib/fesave.h b/src/felib/fesave.h index e7dbc95..95e41ad 100644 --- a/src/felib/fesave.h +++ b/src/felib/fesave.h @@ -45,6 +45,7 @@ inline inputfile &operator >> (inputfile &SaveFile, type &Value) { \ class inputfile; class outputfile; +struct InputFileSaved; typedef std::map valuemap; @@ -73,6 +74,7 @@ private: typedef festring (*InputFileGetVarFn) (inputfile *fl, cfestring &name); + class inputfile { public: inputfile (cfestring &FileName, const valuemap *ValueMap=0, truth AbortOnErr=true); @@ -116,6 +118,10 @@ public: void die (cfestring &msg); + void skipBlanks (); // comments too + + int countArrayItems (char echar); + inline int TokenLine () const { return mTokenLine; } inline int CurrentLine () const { return mCurrentLine; } @@ -153,6 +159,8 @@ protected: int mTokenLine; festring mNumStr; // when reading a number, and `mCollectingNumStr` flag is set, this will be filled truth mCollectingNumStr; + + friend InputFileSaved; }; @@ -196,22 +204,40 @@ void ReadData (festring &, inputfile &); void ReadData (fearray &, inputfile &); void ReadData (fearray &, inputfile &); -//TODO: add ':=' syntax template inline void ReadData (fearray &Array, inputfile &SaveFile) { Array.Clear(); festring Word; SaveFile.ReadWord(Word); - //if (Word == "=") SaveFile.ReadWord(Word); + // one element? if (Word == "==") { Array.Allocate(1); ReadData(Array.Data[0], SaveFile); return; } - if (Word != "=") ABORT("Array syntax error: '=' or '==' expected in file %s, line %u!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); - SaveFile.ReadWord(Word); - if (Word != "{") ABORT("Array syntax error \"%s\" found in file %s, line %u!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + // more than one element typedef typename fearray::sizetype sizetype; - sizetype Size = SaveFile.ReadNumber(); + sizetype Size; + // unknown number of elements? + if (Word == ":=") { + SaveFile.ReadWord(Word); + if (Word != "{") ABORT("Array syntax error \"%s\" found in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + //fprintf(stderr, "counting array items; file: '%s'; line: %u\n", SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + int count = SaveFile.countArrayItems('}'); + // HACK + if (count < 1) ABORT("Array count error found in file %s, line %d!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + Size = count; + //fprintf(stderr, "counted %u array items; file: '%s'; line: %u\n", Size, SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + } else { + if (Word != "=") ABORT("Array syntax error: '=', '==' or ':=' expected in file %s, line %u!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + SaveFile.ReadWord(Word); + if (Word != "{") ABORT("Array syntax error \"%s\" found in file %s, line %u!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + Size = SaveFile.ReadNumber(); + int count = SaveFile.countArrayItems('}'); + if (count < 1) ABORT("Array count error found in file %s, line %d!", SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + //HACK: 2 for vectors, 4 for rects + //if ((sizetype)count != Size && (sizetype)count/2 != Size && (sizetype)count/4 != Size) ABORT("Array count error (%u != %d) found in file %s, line %d!", Size, count, SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + if ((sizetype)count != Size) ABORT("Array count error (%u != %d) found in file %s, line %d!", Size, count, SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); + } Array.Allocate(Size); for (sizetype c = 0; c < Size; ++c) ReadData(Array.Data[c], SaveFile); if (SaveFile.ReadWord() != "}") ABORT("Illegal array terminator \"%s\" encountered in file %s, line %u!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TokenLine()); -- 2.11.4.GIT