--- a/scriptreader.cxx Mon Jul 16 16:15:16 2012 +0300 +++ b/scriptreader.cxx Tue Jul 17 20:35:43 2012 +0300 @@ -45,76 +45,136 @@ #include "common.h" #include "scriptreader.h" -static bool IsWhitespace (char c) { - // These characters are invisible, thus considered whitespace - if (c <= 32 || c == 127 || c == 255) - return true; +ScriptReader::ScriptReader (str path) { + token = ""; + fc = -1; - return false; -} - -ScriptReader::ScriptReader (str path) { - if (!(fp = fopen (path, "r"))) { - error ("couldn't open %s for reading!\n", path.chars ()); - exit (1); - } + for (unsigned int u = 0; u < MAX_FILESTACK; u++) + fp[u] = NULL; - filepath = path; - curline = 1; - curchar = 1; - pos = 0; - token = ""; - atnewline = false; + OpenFile (path); commentmode = 0; } ScriptReader::~ScriptReader () { FinalChecks (); - fclose (fp); + + for (unsigned int u = 0; u < MAX_FILESTACK; u++) { + if (fp[u]) { + ParserWarning ("file idx %u remained open after parsing", u); + CloseFile (u); + } + } +} + +// Opens a file and pushes its pointer to stack +void ScriptReader::OpenFile (str path) { + if (fc+1 >= MAX_FILESTACK) + ParserError ("supposed to open file `%s` but file stack is full! \ + do you have recursive `#include` directives?", + path.chars()); + + // Save the position first. + if (fc != -1) { + savedpos[fc] = ftell (fp[fc]); + } + + fc++; + + fp[fc] = fopen (path, "r"); + if (!fp[fc]) { + ParserError ("couldn't open %s for reading!\n", path.chars ()); + exit (1); + } + + fseek (fp[fc], 0, SEEK_SET); + filepath[fc] = path.chars(); + curline[fc] = 1; + curchar[fc] = 1; + pos[fc] = 0; + atnewline = 0; +} + +void ScriptReader::CloseFile (unsigned int u) { + if (u >= MAX_FILESTACK) + u = fc; + + if (!fp[u]) + return; + + fclose (fp[u]); + fp[u] = NULL; + fc--; + + if (fc != -1) + fseek (fp[fc], savedpos[fc], SEEK_SET); } char ScriptReader::ReadChar () { + if (feof (fp[fc])) + return 0; + char* c = (char*)malloc (sizeof (char)); - if (!fread (c, sizeof (char), 1, fp)) + if (!fread (c, sizeof (char), 1, fp[fc])) return 0; // We're at a newline, thus next char read will begin the next line if (atnewline) { atnewline = false; - curline++; - curchar = 0; // gets incremented to 1 + curline[fc]++; + curchar[fc] = 0; // gets incremented to 1 } - if (c[0] == '\n') + if (c[0] == '\n') { atnewline = true; + + // Check for pre-processor directives + PreprocessDirectives (); + } - curchar++; + curchar[fc]++; return c[0]; } char ScriptReader::PeekChar (int offset) { // Store current position - long curpos = ftell (fp); + long curpos = ftell (fp[fc]); // Forward by offset - fseek (fp, offset, SEEK_CUR); + fseek (fp[fc], offset, SEEK_CUR); // Read the character char* c = (char*)malloc (sizeof (char)); - if (!fread (c, sizeof (char), 1, fp)) + + if (!fread (c, sizeof (char), 1, fp[fc])) { + fseek (fp[fc], curpos, SEEK_SET); return 0; + } // Rewind back - fseek (fp, curpos, SEEK_SET); + fseek (fp[fc], curpos, SEEK_SET); return c[0]; } // true if was found, false if not. -bool ScriptReader::Next () { +bool ScriptReader::Next (bool peek) { str tmp = ""; + // printf ("begin token\n"); - while (!feof (fp)) { + while (1) { + // Check end-of-file + if (feof (fp[fc])) { + // If we're just peeking, we shouldn't + // actually close anything.. + if (peek) + break; + + CloseFile (); + if (fc == -1) + break; + } + // Check if the next token possibly starts a comment. if (PeekChar () == '/' && !tmp.len()) { char c2 = PeekChar (1); @@ -130,6 +190,7 @@ } c = ReadChar (); + // printf ("add char [%d] `%c`\n", c, c); // If this is a comment we're reading, check if this character // gets the comment terminated, otherwise ignore it. @@ -142,8 +203,6 @@ // C-style comments are terminated by a `*/` if (PeekChar() == '/') { commentmode = 0; - // Now the char has to be read in since we - // no longer are reading a comment ReadChar (); } } @@ -161,13 +220,13 @@ (c >= 91 && c <= 96 && c != '_') || (c >= 123 && c <= 126)) { if (tmp.len()) - fseek (fp, ftell (fp) - 1, SEEK_SET); + fseek (fp[fc], ftell (fp[fc]) - 1, SEEK_SET); else tmp += c; break; } - if (IsWhitespace (c)) { + if (IsCharWhitespace (c)) { // Don't break if we haven't gathered anything yet. if (tmp.len()) break; @@ -183,7 +242,7 @@ return false; } - pos++; + pos[fc]++; token = tmp; return true; } @@ -191,17 +250,17 @@ // Returns the next token without advancing the cursor. str ScriptReader::PeekNext () { // Store current position - int cpos = ftell (fp); + int cpos = ftell (fp[fc]); // Advance on the token. - if (!Next ()) + if (!Next (true)) return ""; str tmp = token; // Restore position - fseek (fp, cpos, SEEK_SET); - pos--; + fseek (fp[fc], cpos, SEEK_SET); + pos[fc]--; return tmp; } @@ -209,8 +268,8 @@ void ScriptReader::Seek (unsigned int n, int origin) { switch (origin) { case SEEK_SET: - fseek (fp, 0, SEEK_SET); - pos = 0; + fseek (fp[fc], 0, SEEK_SET); + pos[fc] = 0; break; case SEEK_CUR: break; @@ -238,7 +297,7 @@ void ScriptReader::ParserError (const char* message, ...) { PERFORM_FORMAT (message, outmessage); - ParserMessage ("\nParse error\n", outmessage); + ParserMessage ("\nError: ", outmessage); exit (1); } @@ -248,8 +307,11 @@ } void ScriptReader::ParserMessage (const char* header, char* message) { - fprintf (stderr, "%sIn file %s, at line %u, col %u: %s\n", - header, filepath.chars(), curline, curchar, message); + if (fc >= 0 && fc < MAX_FILESTACK) + fprintf (stderr, "%sIn file %s, at line %u, col %u: %s\n", + header, filepath[fc], curline[fc], curchar[fc], message); + else + fprintf (stderr, "%s%s\n", header, message); } void ScriptReader::MustString () { @@ -259,7 +321,7 @@ // Keep reading characters until we find a terminating quote. while (1) { // can't end here! - if (feof (fp)) + if (feof (fp[fc])) ParserError ("unterminated string"); char c = ReadChar ();