Added pattern preprocessor and #define and #include support
This commit is contained in:
parent
b28d45df8a
commit
4c07983834
@ -20,9 +20,10 @@ add_executable(ImHex
|
||||
source/utils.cpp
|
||||
source/crypto.cpp
|
||||
|
||||
source/parser/lexer.cpp
|
||||
source/parser/parser.cpp
|
||||
source/parser/validator.cpp
|
||||
source/lang/preprocessor.cpp
|
||||
source/lang/lexer.cpp
|
||||
source/lang/parser.cpp
|
||||
source/lang/validator.cpp
|
||||
|
||||
source/provider/file_provider.cpp
|
||||
|
||||
|
@ -15,5 +15,5 @@ using s32 = std::int32_t;
|
||||
using s64 = std::int64_t;
|
||||
using s128 = __int128_t;
|
||||
|
||||
#include "parser/result.hpp"
|
||||
#include "parser/results.hpp"
|
||||
#include "lang/result.hpp"
|
||||
#include "lang/results.hpp"
|
23
include/lang/preprocessor.hpp
Normal file
23
include/lang/preprocessor.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include "token.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <set>
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
class Preprocessor {
|
||||
public:
|
||||
Preprocessor();
|
||||
|
||||
std::pair<Result, std::string> preprocess(const std::string& code, bool applyDefines = true);
|
||||
|
||||
private:
|
||||
std::set<std::pair<std::string, std::string>> m_defines;
|
||||
};
|
||||
|
||||
}
|
13
include/lang/results.hpp
Normal file
13
include/lang/results.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "result.hpp"
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
constexpr Result ResultSuccess(0, 0);
|
||||
|
||||
constexpr Result ResultPreprocessingError(1, 1);
|
||||
constexpr Result ResultLexicalError(2, 1);
|
||||
constexpr Result ResultParseError(3, 1);
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "result.hpp"
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
constexpr Result ResultSuccess(0, 0);
|
||||
|
||||
constexpr Result ResultLexicalError(1, 1);
|
||||
constexpr Result ResultParseError(2, 1);
|
||||
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "parser/token.hpp"
|
||||
#include "lang/token.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "parser/ast_node.hpp"
|
||||
#include "lang/ast_node.hpp"
|
||||
|
||||
#include "views/view.hpp"
|
||||
#include "views/pattern_data.hpp"
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "parser/lexer.hpp"
|
||||
#include "lang/lexer.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
@ -1,4 +1,4 @@
|
||||
#include "parser/parser.hpp"
|
||||
#include "lang/parser.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
120
source/lang/preprocessor.cpp
Normal file
120
source/lang/preprocessor.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "lang/preprocessor.hpp"
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
Preprocessor::Preprocessor() {
|
||||
|
||||
}
|
||||
|
||||
std::pair<Result, std::string> Preprocessor::preprocess(const std::string& code, bool applyDefines) {
|
||||
u32 offset = 0;
|
||||
|
||||
if (applyDefines)
|
||||
this->m_defines.clear();
|
||||
|
||||
std::string output;
|
||||
output.reserve(code.length());
|
||||
|
||||
while (offset < code.length()) {
|
||||
if (code[offset] == '#') {
|
||||
offset += 1;
|
||||
|
||||
if (code.substr(offset, 7) == "include") {
|
||||
offset += 7;
|
||||
|
||||
while (std::isblank(code[offset]) || std::isspace(code[offset]))
|
||||
offset += 1;
|
||||
|
||||
if (code[offset] != '<' && code[offset] != '"')
|
||||
return { ResultPreprocessingError, "" };
|
||||
|
||||
char endChar = code[offset];
|
||||
if (endChar == '<') endChar = '>';
|
||||
|
||||
offset += 1;
|
||||
|
||||
std::string includeFile;
|
||||
while (code[offset] != endChar) {
|
||||
includeFile += code[offset];
|
||||
offset += 1;
|
||||
|
||||
if (offset >= code.length())
|
||||
return { ResultPreprocessingError, "" };
|
||||
}
|
||||
offset += 1;
|
||||
|
||||
if (includeFile[0] != '/')
|
||||
includeFile = "include/" + includeFile;
|
||||
|
||||
FILE *file = fopen(includeFile.c_str(), "r");
|
||||
if (file == nullptr)
|
||||
return { ResultPreprocessingError, "" };
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
char *buffer = new char[size + 1];
|
||||
rewind(file);
|
||||
|
||||
fread(buffer, size, 1, file);
|
||||
buffer[size] = 0x00;
|
||||
|
||||
auto [result, preprocessedInclude] = this->preprocess(buffer, false);
|
||||
if (result.failed())
|
||||
return { ResultPreprocessingError, "" };
|
||||
|
||||
output += preprocessedInclude;
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
fclose(file);
|
||||
} else if (code.substr(offset, 6) == "define") {
|
||||
offset += 6;
|
||||
|
||||
while (std::isblank(code[offset]))
|
||||
offset += 1;
|
||||
|
||||
std::string defineName;
|
||||
while (!std::isblank(code[offset])) {
|
||||
defineName += code[offset];
|
||||
offset += 1;
|
||||
|
||||
if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r')
|
||||
return { ResultPreprocessingError, "" };
|
||||
}
|
||||
|
||||
while (std::isblank(code[offset]))
|
||||
offset += 1;
|
||||
|
||||
std::string replaceValue;
|
||||
do {
|
||||
if (offset >= code.length())
|
||||
return { ResultPreprocessingError, "" };
|
||||
|
||||
replaceValue += code[offset];
|
||||
offset += 1;
|
||||
} while (code[offset] != '\n' && code[offset] != '\r');
|
||||
|
||||
this->m_defines.emplace(defineName, replaceValue);
|
||||
}
|
||||
}
|
||||
|
||||
output += code[offset];
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
if (applyDefines) {
|
||||
for (const auto &[define, value] : this->m_defines) {
|
||||
s32 index = 0;
|
||||
while((index = output.find(define, index)) != std::string::npos) {
|
||||
if (index > 0) {
|
||||
output.replace(index, define.length(), value);
|
||||
index += value.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { ResultSuccess, output };
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
#include "views/view_pattern.hpp"
|
||||
#include <random>
|
||||
|
||||
#include "parser/parser.hpp"
|
||||
#include "parser/lexer.hpp"
|
||||
#include "parser/validator.hpp"
|
||||
#include "lang/preprocessor.hpp"
|
||||
#include "lang/parser.hpp"
|
||||
#include "lang/lexer.hpp"
|
||||
#include "lang/validator.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace hex {
|
||||
@ -98,6 +98,7 @@ namespace hex {
|
||||
delete data;
|
||||
|
||||
this->m_patternData.clear();
|
||||
PatternData::resetPalette();
|
||||
}
|
||||
|
||||
template<std::derived_from<lang::ASTNode> T>
|
||||
@ -112,6 +113,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ViewPattern::parsePattern(char *buffer) {
|
||||
static hex::lang::Preprocessor preprocessor;
|
||||
static hex::lang::Lexer lexer;
|
||||
static hex::lang::Parser parser;
|
||||
static hex::lang::Validator validator;
|
||||
@ -119,8 +121,11 @@ namespace hex {
|
||||
this->clearPatternData();
|
||||
this->postEvent(Events::PatternChanged);
|
||||
|
||||
auto [lexResult, tokens] = lexer.lex(buffer);
|
||||
auto [preprocessingResult, preprocesedCode] = preprocessor.preprocess(buffer);
|
||||
if (preprocessingResult.failed())
|
||||
return;
|
||||
|
||||
auto [lexResult, tokens] = lexer.lex(preprocesedCode);
|
||||
if (lexResult.failed()) {
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user