2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-09-05 00:07:25 +00:00

Add file inclusion for ZCG cpp

This commit is contained in:
Jan
2021-02-10 14:21:58 +01:00
parent 21440daf27
commit d876bc5e25
25 changed files with 779 additions and 2 deletions

View File

@@ -0,0 +1,12 @@
#pragma once
#include "Parsing/IParserLineStream.h"
class CommentRemovingStreamProxy final : IParserLineStream
{
public:
std::string NextLine() override;
bool IncludeFile(const std::string& filename) override;
bool IsOpen() const override;
_NODISCARD bool Eof() const override;
};

View File

@@ -0,0 +1,116 @@
#include "IncludingStreamProxy.h"
#include <sstream>
#include "Parsing/ParsingException.h"
IncludingStreamProxy::IncludingStreamProxy(IParserLineStream* stream)
: m_stream(stream)
{
}
bool IncludingStreamProxy::MatchIncludeDirective(const ParserLine& line) const
{
unsigned includeDirectivePos = 0;
auto hasIncludeDirective = false;
for (; includeDirectivePos < line.m_line.size() - INCLUDE_DIRECTIVE_MINIMUM_TOTAL_LENGTH; includeDirectivePos++)
{
const auto c = line.m_line[includeDirectivePos];
if (isspace(c))
continue;
if (c != '#')
return false;
if (line.m_line.compare(includeDirectivePos + 1, INCLUDE_DIRECTIVE_LENGTH, INCLUDE_DIRECTIVE) != 0)
{
return false;
}
hasIncludeDirective = true;
break;
}
if (!hasIncludeDirective)
return false;
auto currentPos = includeDirectivePos + INCLUDE_DIRECTIVE_LENGTH + 1;
bool isDoubleQuotes;
if (line.m_line[currentPos] == '"')
isDoubleQuotes = true;
else if (line.m_line[currentPos] == '<')
isDoubleQuotes = false;
else
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), INCLUDE_QUOTES_ERROR);
const auto filenameStart = ++currentPos;
unsigned filenameEnd = 0;
auto filenameHasEnd = false;
for (; currentPos < line.m_line.size(); currentPos++)
{
const auto c = line.m_line[currentPos];
if (c == '"')
{
if(!isDoubleQuotes)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), "");
filenameEnd = currentPos;
filenameHasEnd = true;
break;
}
if (c == '>')
{
if (isDoubleQuotes)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), INCLUDE_QUOTES_ERROR);
filenameEnd = currentPos;
filenameHasEnd = true;
break;
}
}
if(!filenameHasEnd)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), INCLUDE_QUOTES_ERROR);
if(filenameEnd <= filenameStart)
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), "No filename specified");
const auto filename = line.m_line.substr(filenameStart, filenameEnd - filenameStart);
if(!m_stream->IncludeFile(filename))
{
std::ostringstream errorStr;
errorStr << "Could not include file \"" << filename << "\"";
throw ParsingException(TokenPos(line.m_filename, line.m_line_number, currentPos), errorStr.str());
}
return true;
}
ParserLine IncludingStreamProxy::NextLine()
{
auto line = m_stream->NextLine();
if (MatchIncludeDirective(line))
return m_stream->NextLine();
return line;
}
bool IncludingStreamProxy::IncludeFile(const std::string& filename)
{
return m_stream->IncludeFile(filename);
}
bool IncludingStreamProxy::IsOpen() const
{
return m_stream->IsOpen();
}
bool IncludingStreamProxy::Eof() const
{
return m_stream->Eof();
}

View File

@@ -0,0 +1,23 @@
#pragma once
#include "Parsing/IParserLineStream.h"
class IncludingStreamProxy final : public IParserLineStream
{
static constexpr const char* INCLUDE_QUOTES_ERROR = "Invalid include directive. Expected \"\" or <>";
static constexpr const char* INCLUDE_DIRECTIVE = "include ";
static constexpr int INCLUDE_DIRECTIVE_LENGTH = std::char_traits<char>::length(INCLUDE_DIRECTIVE);
static constexpr int INCLUDE_DIRECTIVE_MINIMUM_TOTAL_LENGTH = INCLUDE_DIRECTIVE_LENGTH + 1 + 2; // #=+1 ""=+2
IParserLineStream* m_stream;
bool MatchIncludeDirective(const ParserLine& line) const;
public:
explicit IncludingStreamProxy(IParserLineStream* stream);
ParserLine NextLine() override;
bool IncludeFile(const std::string& filename) override;
_NODISCARD bool IsOpen() const override;
_NODISCARD bool Eof() const override;
};

View File

@@ -0,0 +1,93 @@
#include "ParserFilesystemStream.h"
#include <sstream>
#include <filesystem>
namespace fs = std::filesystem;
const std::string ParserFilesystemStream::EMPTY_FILE_NAME;
ParserFilesystemStream::FileInfo::FileInfo(std::string filePath)
: m_file_path(std::move(filePath)),
m_stream(m_file_path),
m_line_number(1)
{
}
ParserFilesystemStream::ParserFilesystemStream(std::string path)
{
m_files.emplace(FileInfo(std::move(path)));
}
bool ParserFilesystemStream::IsOpen() const
{
return !m_files.empty()
&& m_files.top().m_stream.is_open();
}
ParserLine ParserFilesystemStream::NextLine()
{
std::ostringstream str;
auto hasLength = false;
if (m_files.empty())
return ParserLine(EMPTY_FILE_NAME, 0, std::string());
while(!m_files.empty())
{
auto& fileInfo = m_files.top();
auto c = fileInfo.m_stream.get();
while (c != EOF)
{
switch (c)
{
case '\r':
c = fileInfo.m_stream.get();
if (c == '\n')
return ParserLine(fileInfo.m_file_path, fileInfo.m_line_number++, str.str());
str << '\r';
hasLength = true;
continue;
case '\n':
return ParserLine(fileInfo.m_file_path, fileInfo.m_line_number++, str.str());
default:
str << static_cast<char>(c);
hasLength = true;
break;
}
c = fileInfo.m_stream.get();
}
if(hasLength)
return ParserLine(fileInfo.m_file_path, fileInfo.m_line_number, str.str());
m_files.pop();
}
return ParserLine(EMPTY_FILE_NAME, 0, std::string());
}
bool ParserFilesystemStream::IncludeFile(const std::string& filename)
{
if (m_files.empty())
return false;
const auto newFilePath = fs::path(m_files.top().m_file_path).remove_filename().concat(filename);
FileInfo fileInfo(newFilePath.string());
if (!fileInfo.m_stream.is_open())
return false;
m_files.emplace(std::move(fileInfo));
return true;
}
bool ParserFilesystemStream::Eof() const
{
return m_files.empty()
|| m_files.top().m_stream.eof();
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <stack>
#include <fstream>
#include "Parsing/IParserLineStream.h"
class ParserFilesystemStream final : public IParserLineStream
{
static const std::string EMPTY_FILE_NAME;
class FileInfo
{
public:
std::string m_file_path;
std::ifstream m_stream;
int m_line_number;
explicit FileInfo(std::string filePath);
};
std::stack<FileInfo> m_files;
public:
explicit ParserFilesystemStream(std::string path);
ParserLine NextLine() override;
bool IncludeFile(const std::string& filename) override;
_NODISCARD bool IsOpen() const override;
_NODISCARD bool Eof() const override;
};