Pattern Language rewrite (#111)

* Initial parser rewrite effort

Lexer and Token cleanup, Parser started over

* Greatly improved parser syntax

* Reimplemented using declarations and variable placement parsing

* Added back unions and structs

* Added enums as well as mathematical expressions (+, -, *, /, <<, >>, &, |, ^)

* Code style improvement

* Implemented arrays and fixed memory issues

* Fixed more memory issues in parser, reimplemented validator, evaluator and patterns

* Fixed builtin types, arrays and reimplemented strings

* Improved error messages

* Made character a distinct type, used for chars and strings

* Implemented padding, fixed arrays

* Added bitfields

* Added rvalue parsing, no evaluating yet

* Added .idea folder to gitignore

* Fixed build on MacOS

* Added custom implementation of integral concept if not available

* Rebased onto master

* Fixed array variable decl crash

* Added rvalues and dot syntax

* Lower case all pattern language error messages

* Fixed typo in variable name

* Fixed bug where preprocessor would not ignore commented out directives

* Reimplemented pointers

* Fixed rebase issues
This commit is contained in:
WerWolv
2021-01-02 20:27:11 +01:00
committed by GitHub
parent d510f8c7cf
commit 78ef07cf0f
21 changed files with 2204 additions and 1681 deletions

View File

@@ -4,130 +4,351 @@
#include <bit>
#include <optional>
#include <unordered_map>
#include <map>
#include <vector>
namespace hex::lang {
class ASTNode {
public:
enum class Type {
VariableDecl,
TypeDecl,
Struct,
Union,
Enum,
Bitfield,
Scope,
};
constexpr ASTNode() = default;
constexpr virtual ~ASTNode() = default;
constexpr ASTNode(const ASTNode &) = default;
explicit ASTNode(Type type, u32 lineNumber) : m_type(type), m_lineNumber(lineNumber) {}
virtual ~ASTNode() = default;
[[nodiscard]] constexpr u32 getLineNumber() const { return this->m_lineNumber; }
constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; }
Type getType() { return this->m_type; }
u32 getLineNumber() { return this->m_lineNumber; }
virtual ASTNode* clone() = 0;
private:
Type m_type;
u32 m_lineNumber;
u32 m_lineNumber = 1;
};
class ASTNodeVariableDecl : public ASTNode {
class ASTNodeIntegerLiteral : public ASTNode {
public:
explicit ASTNodeVariableDecl(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "", std::optional<u64> offset = { }, size_t arraySize = 1, std::optional<std::string> arraySizeVariable = { }, std::optional<u8> pointerSize = { }, std::optional<std::endian> endianess = { })
: ASTNode(Type::VariableDecl, lineNumber), m_type(type), m_name(name), m_customTypeName(customTypeName), m_offset(offset), m_arraySize(arraySize), m_arraySizeVariable(arraySizeVariable), m_pointerSize(pointerSize), m_endianess(endianess) { }
ASTNodeIntegerLiteral(std::variant<u128, s128> value, Token::ValueType type)
: ASTNode(), m_value(value), m_type(type) {
const Token::TypeToken::Type& getVariableType() const { return this->m_type; }
const std::string& getCustomVariableTypeName() const { return this->m_customTypeName; }
const std::string& getVariableName() const { return this->m_name; };
std::optional<u64> getOffset() const { return this->m_offset; }
size_t getArraySize() const { return this->m_arraySize; }
std::optional<std::string> getArraySizeVariable() const { return this->m_arraySizeVariable; }
std::optional<u8> getPointerSize() const { return this->m_pointerSize; }
std::optional<std::endian> getEndianess() const { return this->m_endianess; }
}
ASTNodeIntegerLiteral(const ASTNodeIntegerLiteral&) = default;
ASTNode* clone() override {
return new ASTNodeIntegerLiteral(*this);
}
[[nodiscard]] const auto& getValue() const {
return this->m_value;
}
[[nodiscard]] Token::ValueType getType() const {
return this->m_type;
}
private:
Token::TypeToken::Type m_type;
std::string m_name, m_customTypeName;
std::optional<u64> m_offset;
size_t m_arraySize;
std::optional<std::string> m_arraySizeVariable;
std::optional<u8> m_pointerSize;
std::optional<std::endian> m_endianess = { };
std::variant<u128, s128> m_value;
Token::ValueType m_type;
};
class ASTNodeScope : public ASTNode {
class ASTNodeNumericExpression : public ASTNode {
public:
explicit ASTNodeScope(u32 lineNumber, std::vector<ASTNode*> nodes) : ASTNode(Type::Scope, lineNumber), m_nodes(nodes) { }
ASTNodeNumericExpression(ASTNode *left, ASTNode *right, Token::Operator op)
: ASTNode(), m_left(left), m_right(right), m_operator(op) { }
~ASTNodeNumericExpression() override {
delete this->m_left;
delete this->m_right;
}
ASTNodeNumericExpression(const ASTNodeNumericExpression &other) : ASTNode(other) {
this->m_operator = other.m_operator;
this->m_left = other.m_left->clone();
this->m_right = other.m_right->clone();
}
ASTNode* clone() override {
return new ASTNodeNumericExpression(*this);
}
ASTNode *getLeftOperand() { return this->m_left; }
ASTNode *getRightOperand() { return this->m_right; }
Token::Operator getOperator() { return this->m_operator; }
std::vector<ASTNode*> &getNodes() { return this->m_nodes; }
private:
std::vector<ASTNode*> m_nodes;
ASTNode *m_left, *m_right;
Token::Operator m_operator;
};
class ASTNodeStruct : public ASTNode {
class ASTNodeBuiltinType : public ASTNode {
public:
explicit ASTNodeStruct(u32 lineNumber, std::string name, std::vector<ASTNode*> nodes)
: ASTNode(Type::Struct, lineNumber), m_name(name), m_nodes(nodes) { }
constexpr explicit ASTNodeBuiltinType(Token::ValueType type)
: ASTNode(), m_type(type) { }
[[nodiscard]] constexpr const auto& getType() const { return this->m_type; }
ASTNode* clone() override {
return new ASTNodeBuiltinType(*this);
}
const std::string& getName() const { return this->m_name; }
std::vector<ASTNode*> &getNodes() { return this->m_nodes; }
private:
std::string m_name;
std::vector<ASTNode*> m_nodes;
};
class ASTNodeUnion : public ASTNode {
public:
explicit ASTNodeUnion(u32 lineNumber, std::string name, std::vector<ASTNode*> nodes)
: ASTNode(Type::Union, lineNumber), m_name(name), m_nodes(nodes) { }
const std::string& getName() const { return this->m_name; }
std::vector<ASTNode*> &getNodes() { return this->m_nodes; }
private:
std::string m_name;
std::vector<ASTNode*> m_nodes;
};
class ASTNodeBitField : public ASTNode {
public:
explicit ASTNodeBitField(u32 lineNumber, std::string name, std::vector<std::pair<std::string, size_t>> fields)
: ASTNode(Type::Bitfield, lineNumber), m_name(name), m_fields(fields) { }
const std::string& getName() const { return this->m_name; }
std::vector<std::pair<std::string, size_t>> &getFields() { return this->m_fields; }
private:
std::string m_name;
std::vector<std::pair<std::string, size_t>> m_fields;
const Token::ValueType m_type;
};
class ASTNodeTypeDecl : public ASTNode {
public:
explicit ASTNodeTypeDecl(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "")
: ASTNode(Type::TypeDecl, lineNumber), m_type(type), m_name(name), m_customTypeName(customTypeName) { }
ASTNodeTypeDecl(std::string_view name, ASTNode *type, std::optional<std::endian> endian = { })
: ASTNode(), m_name(name), m_type(type), m_endian(endian) { }
const std::string& getTypeName() const { return this->m_name; };
ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other) {
this->m_name = other.m_name;
this->m_type = other.m_type->clone();
this->m_endian = other.m_endian;
}
~ASTNodeTypeDecl() override {
delete this->m_type;
}
ASTNode* clone() override {
return new ASTNodeTypeDecl(*this);
}
[[nodiscard]] std::string_view getName() const { return this->m_name; }
[[nodiscard]] ASTNode* getType() { return this->m_type; }
[[nodiscard]] std::optional<std::endian> getEndian() const { return this->m_endian; }
const Token::TypeToken::Type& getAssignedType() const { return this->m_type; }
const std::string& getAssignedCustomTypeName() const { return this->m_customTypeName; }
private:
Token::TypeToken::Type m_type;
std::string m_name, m_customTypeName;
std::string m_name;
ASTNode *m_type;
std::optional<std::endian> m_endian;
};
class ASTNodeVariableDecl : public ASTNode {
public:
ASTNodeVariableDecl(std::string_view name, ASTNode *type, ASTNode *placementOffset = nullptr)
: ASTNode(), m_name(name), m_type(type), m_placementOffset(placementOffset) { }
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other) {
this->m_name = other.m_name;
this->m_type = other.m_type->clone();
if (other.m_placementOffset != nullptr)
this->m_placementOffset = other.m_placementOffset->clone();
else
this->m_placementOffset = nullptr;
}
~ASTNodeVariableDecl() override {
delete this->m_type;
}
ASTNode* clone() override {
return new ASTNodeVariableDecl(*this);
}
[[nodiscard]] std::string_view getName() const { return this->m_name; }
[[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; }
[[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; }
private:
std::string m_name;
ASTNode *m_type;
ASTNode *m_placementOffset;
};
class ASTNodeArrayVariableDecl : public ASTNode {
public:
ASTNodeArrayVariableDecl(std::string_view name, ASTNode *type, ASTNode *size, ASTNode *placementOffset = nullptr)
: ASTNode(), m_name(name), m_type(type), m_size(size), m_placementOffset(placementOffset) { }
ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other) {
this->m_name = other.m_name;
this->m_type = other.m_type->clone();
this->m_size = other.m_size->clone();
if (other.m_placementOffset != nullptr)
this->m_placementOffset = other.m_placementOffset->clone();
else
this->m_placementOffset = nullptr;
}
~ASTNodeArrayVariableDecl() override {
delete this->m_type;
delete this->m_size;
}
ASTNode* clone() override {
return new ASTNodeArrayVariableDecl(*this);
}
[[nodiscard]] std::string_view getName() const { return this->m_name; }
[[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; }
[[nodiscard]] constexpr ASTNode* getSize() const { return this->m_size; }
[[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; }
private:
std::string m_name;
ASTNode *m_type;
ASTNode *m_size;
ASTNode *m_placementOffset;
};
class ASTNodePointerVariableDecl : public ASTNode {
public:
ASTNodePointerVariableDecl(std::string_view name, ASTNode *type, ASTNode *sizeType, ASTNode *placementOffset = nullptr)
: ASTNode(), m_name(name), m_type(type), m_sizeType(sizeType), m_placementOffset(placementOffset) { }
ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other) {
this->m_name = other.m_name;
this->m_type = other.m_type->clone();
this->m_sizeType = other.m_sizeType->clone();
if (other.m_placementOffset != nullptr)
this->m_placementOffset = other.m_placementOffset->clone();
else
this->m_placementOffset = nullptr;
}
~ASTNodePointerVariableDecl() override {
delete this->m_type;
}
ASTNode* clone() override {
return new ASTNodePointerVariableDecl(*this);
}
[[nodiscard]] std::string_view getName() const { return this->m_name; }
[[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; }
[[nodiscard]] constexpr ASTNode* getSizeType() const { return this->m_sizeType; }
[[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; }
private:
std::string m_name;
ASTNode *m_type;
ASTNode *m_sizeType;
ASTNode *m_placementOffset;
};
class ASTNodeStruct : public ASTNode {
public:
ASTNodeStruct() : ASTNode() { }
ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other) {
for (const auto &otherMember : other.getMembers())
this->m_members.push_back(otherMember->clone());
}
~ASTNodeStruct() override {
for (auto &member : this->m_members)
delete member;
}
ASTNode* clone() override {
return new ASTNodeStruct(*this);
}
[[nodiscard]] const std::vector<ASTNode*>& getMembers() const { return this->m_members; }
void addMember(ASTNode *node) { this->m_members.push_back(node); }
private:
std::vector<ASTNode*> m_members;
};
class ASTNodeUnion : public ASTNode {
public:
ASTNodeUnion() : ASTNode() { }
ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other) {
for (const auto &otherMember : other.getMembers())
this->m_members.push_back(otherMember->clone());
}
~ASTNodeUnion() override {
for (auto &member : this->m_members)
delete member;
}
ASTNode* clone() override {
return new ASTNodeUnion(*this);
}
[[nodiscard]] const std::vector<ASTNode*>& getMembers() const { return this->m_members; }
void addMember(ASTNode *node) { this->m_members.push_back(node); }
private:
std::vector<ASTNode*> m_members;
};
class ASTNodeEnum : public ASTNode {
public:
explicit ASTNodeEnum(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name)
: ASTNode(Type::Enum, lineNumber), m_type(type), m_name(name) { }
explicit ASTNodeEnum(ASTNode *underlyingType) : ASTNode(), m_underlyingType(underlyingType) { }
const std::string& getName() const { return this->m_name; };
ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other) {
for (const auto &[name, entry] : other.getEntries())
this->m_entries.emplace_back(name, entry->clone());
this->m_underlyingType = other.m_underlyingType->clone();
}
~ASTNodeEnum() override {
for (auto &[name, expr] : this->m_entries)
delete expr;
delete this->m_underlyingType;
}
ASTNode* clone() override {
return new ASTNodeEnum(*this);
}
[[nodiscard]] const std::vector<std::pair<std::string, ASTNode*>>& getEntries() const { return this->m_entries; }
void addEntry(const std::string &name, ASTNode* expression) { this->m_entries.emplace_back(name, expression); }
[[nodiscard]] const ASTNode *getUnderlyingType() const { return this->m_underlyingType; }
const Token::TypeToken::Type& getUnderlyingType() const { return this->m_type; }
std::vector<std::pair<u64, std::string>>& getValues() { return this->m_values; }
private:
Token::TypeToken::Type m_type;
std::string m_name;
std::vector<std::pair<u64, std::string>> m_values;
std::vector<std::pair<std::string, ASTNode*>> m_entries;
ASTNode *m_underlyingType;
};
class ASTNodeBitfield : public ASTNode {
public:
ASTNodeBitfield() : ASTNode() { }
ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other) {
for (const auto &[name, entry] : other.getEntries())
this->m_entries.emplace_back(name, entry->clone());
}
~ASTNodeBitfield() override {
for (auto &[name, expr] : this->m_entries)
delete expr;
}
ASTNode* clone() override {
return new ASTNodeBitfield(*this);
}
[[nodiscard]] const std::vector<std::pair<std::string, ASTNode*>>& getEntries() const { return this->m_entries; }
void addEntry(const std::string &name, ASTNode* size) { this->m_entries.emplace_back(name, size); }
private:
std::vector<std::pair<std::string, ASTNode*>> m_entries;
};
class ASTNodeRValue : public ASTNode {
public:
explicit ASTNodeRValue(std::vector<std::string> path) : ASTNode(), m_path(std::move(path)) { }
ASTNodeRValue(const ASTNodeRValue&) = default;
ASTNode* clone() override {
return new ASTNodeRValue(*this);
}
const std::vector<std::string>& getPath() {
return this->m_path;
}
private:
std::vector<std::string> m_path;
};
}

View File

@@ -15,7 +15,7 @@ namespace hex::lang {
class Evaluator {
public:
Evaluator(prv::Provider* &provider, std::endian defaultDataEndianess);
Evaluator(prv::Provider* &provider, std::endian defaultDataEndian);
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
@@ -24,18 +24,36 @@ namespace hex::lang {
private:
std::unordered_map<std::string, ASTNode*> m_types;
prv::Provider* &m_provider;
std::endian m_defaultDataEndianess;
std::endian m_defaultDataEndian;
u64 m_currOffset = 0;
std::optional<std::endian> m_currEndian;
std::vector<PatternData*> *m_currMembers = nullptr;
std::pair<u32, std::string> m_error;
std::pair<PatternData*, size_t> createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createBitfieldPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createStringPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createCustomTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createBuiltInTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
using EvaluateError = std::pair<u32, std::string>;
[[noreturn]] static void throwEvaluateError(std::string_view error, u32 lineNumber) {
throw EvaluateError(lineNumber, "Evaluator: " + std::string(error));
}
[[nodiscard]] std::endian getCurrentEndian() const {
return this->m_currEndian.value_or(this->m_defaultDataEndian);
}
ASTNodeIntegerLiteral* evaluateRValue(ASTNodeRValue *node);
ASTNodeIntegerLiteral* evaluateOperator(ASTNodeIntegerLiteral *left, ASTNodeIntegerLiteral *right, Token::Operator op);
ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node);
PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node);
PatternData* evaluateStruct(ASTNodeStruct *node);
PatternData* evaluateUnion(ASTNodeUnion *node);
PatternData* evaluateEnum(ASTNodeEnum *node);
PatternData* evaluateBitfield(ASTNodeBitfield *node);
PatternData* evaluateType(ASTNodeTypeDecl *node);
PatternData* evaluateVariable(ASTNodeVariableDecl *node);
PatternData* evaluateArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluatePointer(ASTNodePointerVariableDecl *node);
};

View File

@@ -20,6 +20,12 @@ namespace hex::lang {
private:
std::pair<u32, std::string> m_error;
using LexerError = std::pair<u32, std::string>;
[[noreturn]] void throwLexerError(std::string_view error, u32 lineNumber) const {
throw LexerError(lineNumber, "Lexer: " + std::string(error));
}
};
}

View File

@@ -1,16 +1,23 @@
#pragma once
#include <hex.hpp>
#include "token.hpp"
#include "ast_node.hpp"
#include "helpers/utils.hpp"
#include <unordered_map>
#include <stdexcept>
#include <utility>
#include <vector>
namespace hex::lang {
class Parser {
public:
Parser();
Parser() = default;
~Parser() = default;
using TokenIter = std::vector<Token>::const_iterator;
@@ -19,31 +26,138 @@ namespace hex::lang {
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::pair<u32, std::string> m_error;
using ParseError = std::pair<u32, std::string>;
ParseError m_error;
TokenIter m_curr;
TokenIter m_originalPosition;
ASTNode* parseBuiltinVariableDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseCustomTypeVariableDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseBuiltinPointerVariableDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseCustomTypePointerVariableDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseBuiltinArrayDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseCustomTypeArrayDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseBuiltinVariableArrayDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseCustomTypeVariableArrayDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parsePaddingDecl(TokenIter &curr);
ASTNode* parseFreeBuiltinVariableDecl(TokenIter &curr, bool hasEndianDef);
ASTNode* parseFreeCustomTypeVariableDecl(TokenIter &curr, bool hasEndianDef);
std::unordered_map<std::string, ASTNode*> m_types;
std::vector<TokenIter> m_matchedOptionals;
ASTNode* parseStruct(TokenIter &curr);
ASTNode* parseUnion(TokenIter &curr);
ASTNode* parseEnum(TokenIter &curr);
ASTNode *parseBitField(TokenIter &curr);
ASTNode *parseScope(TokenIter &curr);
std::optional<ASTNode*> parseUsingDeclaration(TokenIter &curr);
std::optional<std::vector<ASTNode*>> parseStatement(TokenIter &curr);
u32 getLineNumber(s32 index) const {
return this->m_curr[index].lineNumber;
}
template<typename T>
const T& getValue(s32 index) const {
auto value = std::get_if<T>(&this->m_curr[index].value);
if (value == nullptr)
throwParseError("failed to decode token. Invalid type.", getLineNumber(index));
return *value;
}
Token::Type getType(s32 index) const {
return this->m_curr[index].type;
}
ASTNode* parseRValue(std::vector<std::string> &path);
ASTNode* parseFactor();
ASTNode* parseMultiplicativeExpression();
ASTNode* parseAdditiveExpression();
ASTNode* parseShiftExpression();
ASTNode* parseBinaryAndExpression();
ASTNode* parseBinaryXorExpression();
ASTNode* parseBinaryOrExpression();
ASTNode* parseMathematicalExpression();
ASTNode* parseType(s32 startIndex);
ASTNode* parseUsingDeclaration();
ASTNode* parsePadding();
ASTNode* parseMemberVariable();
ASTNode* parseMemberArrayVariable();
ASTNode* parseMemberPointerVariable();
ASTNode* parseStruct();
ASTNode* parseUnion();
ASTNode* parseEnum();
ASTNode* parseBitfield();
ASTNode* parseVariablePlacement();
ASTNode* parseArrayVariablePlacement();
ASTNode* parsePointerVariablePlacement();
ASTNode* parseStatement();
std::vector<ASTNode*> parseTillToken(Token::Type endTokenType, const auto value) {
std::vector<ASTNode*> program;
ScopeExit guard([&]{ for (auto &node : program) delete node; });
while (this->m_curr->type != endTokenType || (*this->m_curr) != value) {
program.push_back(parseStatement());
}
this->m_curr++;
guard.release();
return program;
}
[[noreturn]] void throwParseError(std::string_view error, s32 token = -1) const {
throw ParseError(this->m_curr[token].lineNumber, "Parser: " + std::string(error));
}
/* Token consuming */
bool begin() {
this->m_originalPosition = this->m_curr;
this->m_matchedOptionals.clear();
return true;
}
bool sequence() {
return true;
}
bool sequence(Token::Type type, auto value, auto ... args) {
if (!peek(type, value)) {
this->m_curr = this->m_originalPosition;
return false;
}
this->m_curr++;
if (!sequence(args...)) {
this->m_curr = this->m_originalPosition;
return false;
}
return true;
}
bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) {
if (!peek(type1, value1)) {
if (!peek(type2, value2)) {
this->m_curr = this->m_originalPosition;
return false;
}
}
this->m_curr++;
return true;
}
bool optional(Token::Type type, auto value) {
if (peek(type, value)) {
this->m_matchedOptionals.push_back(this->m_curr);
this->m_curr++;
}
return true;
}
bool peek(Token::Type type, auto value, s32 index = 0) {
return this->m_curr[index].type == type && this->m_curr[index] == value;
}
bool peekOptional(Token::Type type, auto value, u32 index = 0) {
if (index >= this->m_matchedOptionals.size())
return false;
return peek(type, value, std::distance(this->m_curr, this->m_matchedOptionals[index]));
}
std::vector<ASTNode*> parseTillToken(TokenIter &curr, Token::Type endTokenType);
bool tryConsume(TokenIter &curr, std::initializer_list<Token::Type> tokenTypes);
};
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include <hex.hpp>
#include <string>
#include "imgui.h"
#include "imgui_memory_editor.h"
@@ -9,7 +8,9 @@
#include "providers/provider.hpp"
#include "helpers/utils.hpp"
#include <cstring>
#include <random>
#include <string>
namespace hex::lang {
@@ -33,11 +34,9 @@ namespace hex::lang {
class PatternData {
public:
enum class Type { Padding, Unsigned, Signed, Float, Character, String, Struct, Union, Array, Enum };
PatternData(Type type, u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0)
: m_type(type), m_offset(offset), m_size(size), m_name(name), m_endianess(endianess), m_color(color) {
constexpr u32 Palette[] = { 0x50b4771f, 0x500e7fff, 0x502ca02c, 0x502827d6, 0x50bd6794, 0x504b568c, 0x50c277e3, 0x507f7f7f, 0x5022bdbc, 0x50cfbe17 };
PatternData(u64 offset, size_t size, u32 color = 0)
: m_offset(offset), m_size(size), m_color(color) {
constexpr u32 Palette[] = { 0x70b4771f, 0x700e7fff, 0x702ca02c, 0x702827d6, 0x70bd6794, 0x704b568c, 0x70c277e3, 0x707f7f7f, 0x7022bdbc, 0x70cfbe17 };
if (color != 0)
return;
@@ -49,21 +48,25 @@ namespace hex::lang {
}
virtual ~PatternData() = default;
[[nodiscard]] Type getPatternType() const { return this->m_type; }
virtual PatternData* clone() = 0;
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
[[nodiscard]] size_t getSize() const { return this->m_size; }
[[nodiscard]] const std::string& getName() const { return this->m_name; }
void setName(std::string name) { this->m_name = name; }
[[nodiscard]] const std::string& getVariableName() const { return this->m_variableName; }
void setVariableName(std::string name) { this->m_variableName = std::move(name); }
[[nodiscard]] const std::string& getTypeName() const { return this->m_typeName; }
void setTypeName(std::string name) { this->m_typeName = std::move(name); }
[[nodiscard]] u32 getColor() const { return this->m_color; }
void setColor(u32 color) { this->m_color = color; }
[[nodiscard]] std::endian getEndianess() const { return this->m_endianess; }
void setEndianess(std::endian endianess) { this->m_endianess = endianess; }
[[nodiscard]] std::endian getEndian() const { return this->m_endian; }
void setEndian(std::endian endian) { this->m_endian = endian; }
virtual void createEntry(prv::Provider* &provider) = 0;
virtual std::string getTypeName() = 0;
[[nodiscard]] virtual std::string getFormattedName() const = 0;
virtual std::optional<u32> highlightBytes(size_t offset) {
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()))
@@ -77,9 +80,9 @@ namespace hex::lang {
static bool sortPatternDataTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, lang::PatternData* left, lang::PatternData* right) {
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getName() > right->getName();
return left->getVariableName() > right->getVariableName();
else
return left->getName() < right->getName();
return left->getVariableName() < right->getVariableName();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
@@ -100,9 +103,9 @@ namespace hex::lang {
provider->read(left->getOffset(), leftBuffer.data(), left->getSize());
provider->read(right->getOffset(), rightBuffer.data(), right->getSize());
if (left->m_endianess != std::endian::native)
if (left->m_endian != std::endian::native)
std::reverse(leftBuffer.begin(), leftBuffer.end());
if (right->m_endianess != std::endian::native)
if (right->m_endian != std::endian::native)
std::reverse(rightBuffer.begin(), rightBuffer.end());
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
@@ -129,38 +132,38 @@ namespace hex::lang {
static void resetPalette() { PatternData::s_paletteOffset = 0; }
protected:
void createDefaultEntry(std::string value) {
void createDefaultEntry(std::string_view value) const {
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
ImGui::TableNextColumn();
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
Region selectRegion = { this->getOffset(), this->getSize() };
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
}
ImGui::SameLine();
ImGui::Text("%s", this->getName().c_str());
ImGui::Text("%s", this->getVariableName().c_str());
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getTypeName().c_str());
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getFormattedName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", value.c_str());
ImGui::Text("%s", value.data());
}
protected:
std::endian m_endianess = std::endian::native;
std::endian m_endian = std::endian::native;
private:
Type m_type;
u64 m_offset;
size_t m_size;
u32 m_color;
std::string m_name;
std::string m_variableName;
std::string m_typeName;
static inline u8 s_paletteOffset = 0;
@@ -168,41 +171,49 @@ namespace hex::lang {
class PatternDataPadding : public PatternData {
public:
PatternDataPadding(u64 offset, size_t size) : PatternData(Type::Padding, offset, size, "", { }, 0x00FFFFFF) { }
PatternDataPadding(u64 offset, size_t size) : PatternData(offset, size, 0x00FFFFFF) { }
PatternData* clone() override {
return new PatternDataPadding(*this);
}
void createEntry(prv::Provider* &provider) override {
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
return "";
}
};
class PatternDataPointer : public PatternData {
public:
PatternDataPointer(u64 offset, size_t size, const std::string &name, PatternData *pointedAt, std::endian endianess, u32 color = 0)
: PatternData(Type::Unsigned, offset, size, name, endianess, color), m_pointedAt(pointedAt) {
this->m_pointedAt->setName("*" + this->m_pointedAt->getName());
PatternDataPointer(u64 offset, size_t size, PatternData *pointedAt, u32 color = 0)
: PatternData(offset, size, color), m_pointedAt(pointedAt) {
this->m_pointedAt->setVariableName("*" + this->m_pointedAt->getVariableName());
}
PatternData* clone() override {
return new PatternDataPointer(*this);
}
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), this->m_endianess);
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getTypeName().c_str());
ImGui::TextColored(ImColor(0xFF9BC64D), "%s*", this->m_pointedAt->getFormattedName().c_str());
ImGui::TableNextColumn();
ImGui::Text("*(0x%0*llx)", this->getSize() * 2, data);
ImGui::Text("*(0x%llx)", data);
if (open) {
this->m_pointedAt->createEntry(provider);
@@ -211,7 +222,7 @@ namespace hex::lang {
}
}
virtual std::optional<u32> highlightBytes(size_t offset) {
std::optional<u32> highlightBytes(size_t offset) override {
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()))
return this->getColor();
else if (auto color = this->m_pointedAt->highlightBytes(offset); color.has_value())
@@ -220,7 +231,7 @@ namespace hex::lang {
return { };
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
return "Pointer";
}
@@ -230,18 +241,22 @@ namespace hex::lang {
class PatternDataUnsigned : public PatternData {
public:
PatternDataUnsigned(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0)
: PatternData(Type::Unsigned, offset, size, name, endianess, color) { }
PatternDataUnsigned(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternData* clone() override {
return new PatternDataUnsigned(*this);
}
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), this->m_endianess);
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
this->createDefaultEntry(hex::format("%lu (0x%0*lx)", data, this->getSize() * 2, data));
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
switch (this->getSize()) {
case 1: return "u8";
case 2: return "u16";
@@ -255,20 +270,24 @@ namespace hex::lang {
class PatternDataSigned : public PatternData {
public:
PatternDataSigned(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0)
: PatternData(Type::Signed, offset, size, name, endianess, color) { }
PatternDataSigned(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternData* clone() override {
return new PatternDataSigned(*this);
}
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), this->m_endianess);
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64);
s64 signedData = hex::signExtend(data, this->getSize(), 64);
this->createDefaultEntry(hex::format("%ld (0x%0*lx)", signedData, this->getSize() * 2, data));
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
switch (this->getSize()) {
case 1: return "s8";
case 2: return "s16";
@@ -282,21 +301,25 @@ namespace hex::lang {
class PatternDataFloat : public PatternData {
public:
PatternDataFloat(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0)
: PatternData(Type::Float, offset, size, name, endianess, color) { }
PatternDataFloat(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternData* clone() override {
return new PatternDataFloat(*this);
}
void createEntry(prv::Provider* &provider) override {
double formatData = 0;
if (this->getSize() == 4) {
float data = 0;
provider->read(this->getOffset(), &data, 4);
data = hex::changeEndianess(data, 4, this->m_endianess);
data = hex::changeEndianess(data, 4, this->getEndian());
formatData = data;
} else if (this->getSize() == 8) {
double data = 0;
provider->read(this->getOffset(), &data, 8);
data = hex::changeEndianess(data, 8, this->m_endianess);
data = hex::changeEndianess(data, 8, this->getEndian());
formatData = data;
}
@@ -304,7 +327,7 @@ namespace hex::lang {
this->createDefaultEntry(hex::format("%f (0x%0*lx)", formatData, this->getSize() * 2, formatData));
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
switch (this->getSize()) {
case 4: return "float";
case 8: return "double";
@@ -315,8 +338,12 @@ namespace hex::lang {
class PatternDataCharacter : public PatternData {
public:
PatternDataCharacter(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0)
: PatternData(Type::Character, offset, size, name, endianess, color) { }
explicit PatternDataCharacter(u64 offset, u32 color = 0)
: PatternData(offset, 1, color) { }
PatternData* clone() override {
return new PatternDataCharacter(*this);
}
void createEntry(prv::Provider* &provider) override {
char character;
@@ -325,15 +352,19 @@ namespace hex::lang {
this->createDefaultEntry(hex::format("'%c'", character));
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
return "Character";
}
};
class PatternDataString : public PatternData {
public:
PatternDataString(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0)
: PatternData(Type::String, offset, size, name, endianess, color) { }
PatternDataString(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternData* clone() override {
return new PatternDataString(*this);
}
void createEntry(prv::Provider* &provider) override {
std::vector<u8> buffer(this->getSize() + 1, 0x00);
@@ -343,15 +374,24 @@ namespace hex::lang {
this->createDefaultEntry(hex::format("\"%s\"", makeDisplayable(buffer.data(), this->getSize()).c_str()));
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
return "String";
}
};
class PatternDataArray : public PatternData {
public:
PatternDataArray(u64 offset, size_t size, const std::string &name, std::endian endianess, const std::vector<PatternData*> & entries, u32 color = 0)
: PatternData(Type::Array, offset, size, name, endianess, color), m_entries(entries) { }
PatternDataArray(u64 offset, size_t size, std::vector<PatternData*> entries, u32 color = 0)
: PatternData(offset, size, color), m_entries(std::move(entries)) { }
PatternDataArray(const PatternDataArray &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
for (const auto &entry : other.m_entries)
this->m_entries.push_back(entry->clone());
}
PatternData* clone() override {
return new PatternDataArray(*this);
}
void createEntry(prv::Provider* &provider) override {
if (this->m_entries.empty())
@@ -359,13 +399,13 @@ namespace hex::lang {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str());
ImGui::SameLine(0, 0);
@@ -396,7 +436,7 @@ namespace hex::lang {
return { };
}
std::string getTypeName() override {
[[nodiscard]] std::string getFormattedName() const override {
return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]";
}
@@ -406,20 +446,29 @@ namespace hex::lang {
class PatternDataStruct : public PatternData {
public:
PatternDataStruct(u64 offset, size_t size, const std::string &name, std::endian endianess, const std::string &structName, const std::vector<PatternData*> & members, u32 color = 0)
: PatternData(Type::Struct, offset, size, name, endianess, color), m_structName(structName), m_members(members), m_sortedMembers(members) { }
PatternDataStruct(u64 offset, size_t size, const std::vector<PatternData*> & members, u32 color = 0)
: PatternData(offset, size, color), m_members(members), m_sortedMembers(members) { }
PatternDataStruct(const PatternDataStruct &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
for (const auto &member : other.m_members)
this->m_members.push_back(member->clone());
}
PatternData* clone() override {
return new PatternDataStruct(*this);
}
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->m_structName.c_str());
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
@@ -452,32 +501,44 @@ namespace hex::lang {
member->sort(sortSpecs, provider);
}
std::string getTypeName() override {
return "struct " + this->m_structName;
[[nodiscard]] std::string getFormattedName() const override {
return "struct " + PatternData::getTypeName();
}
const auto& getMembers() const {
return this->m_members;
}
private:
std::string m_structName;
std::vector<PatternData*> m_members;
std::vector<PatternData*> m_sortedMembers;
};
class PatternDataUnion : public PatternData {
public:
PatternDataUnion(u64 offset, size_t size, const std::string &name, const std::string &unionName, const std::vector<PatternData*> & members, std::endian endianess, u32 color = 0)
: PatternData(Type::Union, offset, size, name, endianess, color), m_unionName(unionName), m_members(members), m_sortedMembers(members) { }
PatternDataUnion(u64 offset, size_t size, const std::vector<PatternData*> & members, u32 color = 0)
: PatternData(offset, size, color), m_members(members), m_sortedMembers(members) { }
PatternDataUnion(const PatternDataUnion &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
for (const auto &member : other.m_members)
this->m_members.push_back(member->clone());
}
PatternData* clone() override {
return new PatternDataUnion(*this);
}
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", this->m_unionName.c_str());
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
@@ -511,27 +572,34 @@ namespace hex::lang {
member->sort(sortSpecs, provider);
}
std::string getTypeName() override {
return "union " + this->m_unionName;
[[nodiscard]] std::string getFormattedName() const override {
return "union " + PatternData::getTypeName();;
}
const auto& getMembers() const {
return this->m_members;
}
private:
std::string m_unionName;
std::vector<PatternData*> m_members;
std::vector<PatternData*> m_sortedMembers;
};
class PatternDataEnum : public PatternData {
public:
PatternDataEnum(u64 offset, size_t size, const std::string &name, const std::string &enumName, std::vector<std::pair<u64, std::string>> enumValues, std::endian endianess, u32 color = 0)
: PatternData(Type::Enum, offset, size, name, endianess, color), m_enumName(enumName), m_enumValues(enumValues) { }
PatternDataEnum(u64 offset, size_t size, std::vector<std::pair<u64, std::string>> enumValues, u32 color = 0)
: PatternData(offset, size, color), m_enumValues(std::move(enumValues)) { }
PatternData* clone() override {
return new PatternDataEnum(*this);
}
void createEntry(prv::Provider* &provider) override {
u64 value = 0;
provider->read(this->getOffset(), &value, this->getSize());
value = hex::changeEndianess(value, this->getSize(), this->m_endianess);
value = hex::changeEndianess(value, this->getSize(), this->getEndian());
std::string valueString = this->m_enumName + "::";
std::string valueString = PatternData::getTypeName() + "::";
bool foundValue = false;
for (auto &[entryValue, entryName] : this->m_enumValues) {
@@ -546,69 +614,84 @@ namespace hex::lang {
valueString += "???";
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
Region selectRegion = { this->getOffset(), this->getSize() };
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
}
ImGui::SameLine();
ImGui::Text("%s", this->getName().c_str());
ImGui::Text("%s", this->getVariableName().c_str());
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "enum"); ImGui::SameLine(); ImGui::Text("%s", this->m_enumName.c_str());
ImGui::TextColored(ImColor(0xFFD69C56), "enum"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", hex::format("%s (0x%0*lx)", valueString.c_str(), this->getSize() * 2, value).c_str());
}
std::string getTypeName() override {
return "enum " + this->m_enumName;
[[nodiscard]] std::string getFormattedName() const override {
return "enum " + PatternData::getTypeName();
}
const auto& getEnumValues() const {
return this->m_enumValues;
}
private:
std::string m_enumName;
std::vector<std::pair<u64, std::string>> m_enumValues;
};
class PatternDataBitfield : public PatternData {
public:
PatternDataBitfield(u64 offset, size_t size, const std::string &name, const std::string &bitfieldName, std::vector<std::pair<std::string, size_t>> fields, std::endian endianess, u32 color = 0)
: PatternData(Type::Enum, offset, size, name, endianess, color), m_bitfieldName(bitfieldName), m_fields(fields) { }
PatternDataBitfield(u64 offset, size_t size, std::vector<std::pair<std::string, size_t>> fields, u32 color = 0)
: PatternData(offset, size, color), m_fields(std::move(fields)) { }
PatternData* clone() override {
return new PatternDataBitfield(*this);
}
void createEntry(prv::Provider* &provider) override {
u64 value = 0;
provider->read(this->getOffset(), &value, this->getSize());
value = hex::changeEndianess(value, this->getSize(), this->m_endianess);
std::vector<u8> value(this->getSize(), 0);
provider->read(this->getOffset(), &value[0], value.size());
if (this->m_endian == std::endian::big)
std::reverse(value.begin(), value.end());
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04lx", this->getSize());
ImGui::Text("0x%04llx", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", this->m_bitfieldName.c_str());
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("{ %llx }", value);
std::string valueString = "{ ";
for (u64 i = 0; i < value.size(); i++)
valueString += hex::format("%02x ", value[i]);
valueString += "}";
ImGui::TextUnformatted(valueString.c_str());
if (open) {
u16 bitOffset = 0;
for (auto &[entryName, entrySize] : this->m_fields) {
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::Text("%s", entryName.c_str());
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3) - 1);
ImGui::Text("0x%08llx : 0x%08llx", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3));
ImGui::TableNextColumn();
if (entrySize == 1)
ImGui::Text("%llu bit", entrySize);
@@ -617,7 +700,11 @@ namespace hex::lang {
ImGui::TableNextColumn();
ImGui::Text("%s", entryName.c_str());
ImGui::TableNextColumn();
ImGui::Text("%llx", hex::extract((bitOffset + entrySize) - 1, bitOffset, value));
{
u128 fieldValue = 0;
std::memcpy(&fieldValue, value.data() + (bitOffset / 8), (entrySize / 8) + 1);
ImGui::Text("%llx", hex::extract((bitOffset + entrySize) - 1 - ((bitOffset / 8) * 8), bitOffset - ((bitOffset / 8) * 8), fieldValue));
}
bitOffset += entrySize;
}
@@ -626,12 +713,15 @@ namespace hex::lang {
}
std::string getTypeName() override {
return "bitfield " + this->m_bitfieldName;
[[nodiscard]] std::string getFormattedName() const override {
return "bitfield " + PatternData::getTypeName();
}
const auto& getFields() const {
return this->m_fields;
}
private:
std::string m_bitfieldName;
std::vector<std::pair<std::string, size_t>> m_fields;
};

View File

@@ -18,12 +18,18 @@ namespace hex::lang {
std::optional<std::string> preprocess(const std::string& code, bool initialRun = true);
void addPragmaHandler(std::string pragmaType, std::function<bool(std::string)> function);
void addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string&)> &function);
void addDefaultPragmaHandlers();
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
using PreprocessorError = std::pair<u32, std::string>;
[[noreturn]] void throwPreprocessorError(std::string_view error, u32 lineNumber) const {
throw PreprocessorError(lineNumber, "Preprocessor: " + std::string(error));
}
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
std::set<std::pair<std::string, std::string>> m_defines;

View File

@@ -2,86 +2,209 @@
#include <hex.hpp>
#include "helpers/utils.hpp"
#include <string>
#include <variant>
namespace hex::lang {
struct Token {
class Token {
public:
enum class Type : u64 {
Keyword,
Type,
ValueType,
Operator,
Integer,
Identifier,
Separator
};
enum class Keyword {
Struct,
Union,
Using,
Enum,
Bitfield,
LittleEndian,
BigEndian,
};
enum class Operator {
AtDeclaration,
Assignment,
Inherit,
Plus,
Minus,
Star,
Slash,
ShiftLeft,
ShiftRight,
BitOr,
BitAnd,
BitXor
};
enum class ValueType {
Unsigned8Bit = 0x10,
Signed8Bit = 0x11,
Unsigned16Bit = 0x20,
Signed16Bit = 0x21,
Unsigned32Bit = 0x40,
Signed32Bit = 0x41,
Unsigned64Bit = 0x80,
Signed64Bit = 0x81,
Unsigned128Bit = 0x100,
Signed128Bit = 0x101,
Character = 0x13,
Float = 0x42,
Double = 0x82,
CustomType = 0x00,
Padding = 0x1F,
Unsigned = 0xFF00,
Signed = 0xFF01,
FloatingPoint = 0xFF02,
Integer = 0xFF03,
Any = 0xFFFF
};
enum class Separator {
RoundBracketOpen,
RoundBracketClose,
CurlyBracketOpen,
CurlyBracketClose,
SquareBracketOpen,
SquareBracketClose,
Comma,
Dot,
EndOfExpression,
ScopeOpen,
ScopeClose,
ArrayOpen,
ArrayClose,
Separator,
EndOfProgram
} type;
};
struct KeywordToken {
enum class Keyword {
Struct,
Union,
Using,
Enum,
Bitfield,
LittleEndian,
BigEndian
} keyword;
} keywordToken;
struct IdentifierToken {
std::string identifier;
} identifierToken;
struct OperatorToken {
enum class Operator {
AtDeclaration,
Assignment,
Inherit,
Star
} op;
} operatorToken;
struct IntegerToken {
s128 integer;
} integerToken;
struct TypeToken {
enum class Type {
Unsigned8Bit = 0x10,
Signed8Bit = 0x11,
Unsigned16Bit = 0x20,
Signed16Bit = 0x21,
Unsigned32Bit = 0x40,
Signed32Bit = 0x41,
Unsigned64Bit = 0x80,
Signed64Bit = 0x81,
Unsigned128Bit = 0x100,
Signed128Bit = 0x101,
Float = 0x42,
Double = 0x82,
CustomType = 0x00,
Padding = 0x1F
} type;
} typeToken;
using ValueTypes = std::variant<Keyword, std::string, Operator, s128, ValueType, Separator>;
u32 lineNumber;
Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) {
[[nodiscard]] constexpr static inline bool isUnsigned(const TypeToken::Type type) {
}
[[nodiscard]] constexpr static inline bool isUnsigned(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x00;
}
[[nodiscard]] constexpr static inline bool isSigned(const TypeToken::Type type) {
[[nodiscard]] constexpr static inline bool isSigned(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x01;
}
[[nodiscard]] constexpr static inline bool isFloatingPoint(const TypeToken::Type type) {
[[nodiscard]] constexpr static inline bool isFloatingPoint(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x02;
}
[[nodiscard]] constexpr static inline u32 getTypeSize(const TypeToken::Type type) {
[[nodiscard]] constexpr static inline u32 getTypeSize(const ValueType type) {
return static_cast<u32>(type) >> 4;
}
[[nodiscard]] constexpr static auto getTypeName(const lang::Token::ValueType type) {
switch (type) {
case ValueType::Signed8Bit: return "s8";
case ValueType::Signed16Bit: return "s16";
case ValueType::Signed32Bit: return "s32";
case ValueType::Signed64Bit: return "s64";
case ValueType::Signed128Bit: return "s128";
case ValueType::Unsigned8Bit: return "u8";
case ValueType::Unsigned16Bit: return "u16";
case ValueType::Unsigned32Bit: return "u32";
case ValueType::Unsigned64Bit: return "u64";
case ValueType::Unsigned128Bit: return "u128";
case ValueType::Float: return "float";
case ValueType::Double: return "double";
case ValueType::Character: return "char";
default: return "< ??? >";
}
}
bool operator==(const ValueTypes &other) const {
if (this->type == Type::Integer || this->type == Type::Identifier)
return true;
else if (this->type == Type::ValueType) {
auto otherValueType = std::get_if<ValueType>(&other);
auto valueType = std::get_if<ValueType>(&this->value);
if (otherValueType == nullptr) return false;
if (valueType == nullptr) return false;
if (*otherValueType == *valueType)
return true;
else if (*otherValueType == ValueType::Any)
return *valueType != ValueType::CustomType && *valueType != ValueType::Padding;
else if (*otherValueType == ValueType::Unsigned)
return isUnsigned(*valueType);
else if (*otherValueType == ValueType::Signed)
return isSigned(*valueType);
else if (*otherValueType == ValueType::FloatingPoint)
return isFloatingPoint(*valueType);
else if (*otherValueType == ValueType::Integer)
return isUnsigned(*valueType) || isSigned(*valueType);
}
else
return other == this->value;
return false;
}
bool operator!=(const ValueTypes &other) const {
return !operator==(other);
}
Type type;
ValueTypes value;
u32 lineNumber;
};
}
}
#define COMPONENT(type, value) hex::lang::Token::Type::type, hex::lang::Token::type::value
#define KEYWORD_STRUCT COMPONENT(Keyword, Struct)
#define KEYWORD_UNION COMPONENT(Keyword, Union)
#define KEYWORD_USING COMPONENT(Keyword, Using)
#define KEYWORD_ENUM COMPONENT(Keyword, Enum)
#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield)
#define KEYWORD_LE COMPONENT(Keyword, LittleEndian)
#define KEYWORD_BE COMPONENT(Keyword, BigEndian)
#define INTEGER hex::lang::Token::Type::Integer, 0xFFFF'FFFF'FFFF'FFFF
#define IDENTIFIER hex::lang::Token::Type::Identifier, ""
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)
#define OPERATOR_INHERIT COMPONENT(Operator, Inherit)
#define OPERATOR_PLUS COMPONENT(Operator, Plus)
#define OPERATOR_MINUS COMPONENT(Operator, Minus)
#define OPERATOR_STAR COMPONENT(Operator, Star)
#define OPERATOR_SLASH COMPONENT(Operator, Slash)
#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft)
#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight)
#define OPERATOR_BITOR COMPONENT(Operator, BitOr)
#define OPERATOR_BITAND COMPONENT(Operator, BitAnd)
#define OPERATOR_BITXOR COMPONENT(Operator, BitXor)
#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType)
#define VALUETYPE_PADDING COMPONENT(ValueType, Padding)
#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned)
#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed)
#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint)
#define VALUETYPE_INTEGER COMPONENT(ValueType, Integer)
#define VALUETYPE_ANY COMPONENT(ValueType, Any)
#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen)
#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose)
#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen)
#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose)
#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen)
#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose)
#define SEPARATOR_COMMA COMPONENT(Separator, Comma)
#define SEPARATOR_DOT COMPONENT(Separator, Dot)
#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression)
#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram)

View File

@@ -15,11 +15,19 @@ namespace hex::lang {
Validator();
bool validate(const std::vector<ASTNode*>& ast);
void printAST(const std::vector<ASTNode*>& ast);
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::pair<u32, std::string> m_error;
using ValidatorError = std::pair<u32, std::string>;
[[noreturn]] void throwValidateError(std::string_view error, u32 lineNumber) const {
throw ValidatorError(lineNumber, error);
}
};
}

View File

@@ -9,6 +9,7 @@
#include <cstring>
#include <filesystem>
#include <thread>
#include "ImGuiFileBrowser.h"
#include "TextEditor.h"