Implemented bitfield support into the pattern language
This commit is contained in:
parent
2f78a10e4c
commit
e3cb078306
@ -15,6 +15,7 @@ namespace hex::lang {
|
||||
TypeDecl,
|
||||
Struct,
|
||||
Enum,
|
||||
Bitfield,
|
||||
Scope,
|
||||
};
|
||||
|
||||
@ -66,6 +67,18 @@ namespace hex::lang {
|
||||
std::vector<ASTNode*> m_nodes;
|
||||
};
|
||||
|
||||
class ASTNodeBitField : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeBitField(std::string name, std::vector<std::pair<std::string, size_t>> fields)
|
||||
: ASTNode(Type::Bitfield), 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;
|
||||
};
|
||||
|
||||
class ASTNodeTypeDecl : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeTypeDecl(const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "")
|
||||
|
@ -22,6 +22,7 @@ namespace hex::lang {
|
||||
|
||||
std::pair<PatternData*, size_t> createStructPattern(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);
|
||||
|
@ -117,7 +117,6 @@ namespace hex::lang {
|
||||
|
||||
protected:
|
||||
void createDefaultEntry(std::string value) {
|
||||
static u64 id = 0;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
@ -125,7 +124,7 @@ namespace hex::lang {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", this->getName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize());
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04lx", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
@ -267,7 +266,7 @@ namespace hex::lang {
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize());
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04lx", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
@ -312,7 +311,7 @@ namespace hex::lang {
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize());
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04lx", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
@ -394,5 +393,65 @@ namespace hex::lang {
|
||||
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, u32 color = 0)
|
||||
: PatternData(Type::Enum, offset, size, name, color), m_bitfieldName(bitfieldName), m_fields(fields) { }
|
||||
|
||||
void createEntry(prv::Provider* &provider) override {
|
||||
u64 value = 0;
|
||||
provider->read(this->getOffset(), &value, this->getSize());
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(0x00FFFFFF), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_AlphaPreview);
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%04lx", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", this->getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", "{ ... }");
|
||||
|
||||
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::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", entryName.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3) - 1);
|
||||
ImGui::TableNextColumn();
|
||||
if (entrySize == 1)
|
||||
ImGui::Text("%llu bit", entrySize);
|
||||
else
|
||||
ImGui::Text("%llu bits", entrySize);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", entryName.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%llx", hex::extract((bitOffset + entrySize) - 1, bitOffset, value));
|
||||
bitOffset += entrySize;
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string getTypeName() override {
|
||||
return "bitfield " + this->m_bitfieldName;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_bitfieldName;
|
||||
std::vector<std::pair<std::string, size_t>> m_fields;
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -26,7 +26,8 @@ namespace hex::lang {
|
||||
enum class Keyword {
|
||||
Struct,
|
||||
Using,
|
||||
Enum
|
||||
Enum,
|
||||
Bitfield
|
||||
} keyword;
|
||||
} keywordToken;
|
||||
struct IdentifierToken {
|
||||
|
@ -75,6 +75,11 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const u64 &value) {
|
||||
u64 mask = (std::numeric_limits<u64>::max() >> (63 - (from - to))) << to;
|
||||
return (value & mask) >> to;
|
||||
}
|
||||
|
||||
|
||||
class ScopeExit {
|
||||
public:
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "lang/evaluator.hpp"
|
||||
|
||||
#include <bit>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace hex::lang {
|
||||
@ -87,6 +88,22 @@ namespace hex::lang {
|
||||
return { new PatternDataEnum(offset, size, varDeclNode->getVariableName(), enumType->getName(), enumType->getValues()), size };
|
||||
}
|
||||
|
||||
std::pair<PatternData*, size_t> Evaluator::createBitfieldPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
|
||||
|
||||
auto *bitfieldType = static_cast<ASTNodeBitField*>(this->m_types[varDeclNode->getCustomVariableTypeName()]);
|
||||
|
||||
if (bitfieldType == nullptr)
|
||||
return { nullptr, 0 };
|
||||
|
||||
size_t size = 0;
|
||||
for (auto &[fieldName, fieldSize] : bitfieldType->getFields())
|
||||
size += fieldSize;
|
||||
|
||||
size = std::bit_ceil(size) / 8;
|
||||
|
||||
return { new PatternDataBitfield(offset, size, varDeclNode->getVariableName(), bitfieldType->getName(), bitfieldType->getFields()), size };
|
||||
}
|
||||
|
||||
std::pair<PatternData*, size_t> Evaluator::createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
|
||||
std::vector<PatternData*> entries;
|
||||
|
||||
@ -135,6 +152,8 @@ namespace hex::lang {
|
||||
return this->createStructPattern(varDeclNode, offset);
|
||||
case ASTNode::Type::Enum:
|
||||
return this->createEnumPattern(varDeclNode, offset);
|
||||
case ASTNode::Type::Bitfield:
|
||||
return this->createBitfieldPattern(varDeclNode, offset);
|
||||
case ASTNode::Type::TypeDecl:
|
||||
return this->createBuiltInTypePattern(varDeclNode, offset);
|
||||
}
|
||||
@ -195,6 +214,12 @@ namespace hex::lang {
|
||||
this->m_types.emplace(enumNode->getName(), enumNode);
|
||||
}
|
||||
break;
|
||||
case ASTNode::Type::Bitfield:
|
||||
{
|
||||
auto *bitfieldNode = static_cast<ASTNodeBitField*>(node);
|
||||
this->m_types.emplace(bitfieldNode->getName(), bitfieldNode);
|
||||
}
|
||||
break;
|
||||
case ASTNode::Type::TypeDecl:
|
||||
{
|
||||
auto *typeDeclNode = static_cast<ASTNodeTypeDecl*>(node);
|
||||
|
@ -102,31 +102,31 @@ namespace hex::lang {
|
||||
if (std::isblank(c) || std::isspace(c)) {
|
||||
offset += 1;
|
||||
} else if (c == ';') {
|
||||
tokens.push_back({.type = Token::Type::EndOfExpression});
|
||||
tokens.push_back({ .type = Token::Type::EndOfExpression });
|
||||
offset += 1;
|
||||
} else if (c == '{') {
|
||||
tokens.push_back({.type = Token::Type::ScopeOpen});
|
||||
tokens.push_back({ .type = Token::Type::ScopeOpen });
|
||||
offset += 1;
|
||||
} else if (c == '}') {
|
||||
tokens.push_back({.type = Token::Type::ScopeClose});
|
||||
tokens.push_back({ .type = Token::Type::ScopeClose });
|
||||
offset += 1;
|
||||
} else if (c == '[') {
|
||||
tokens.push_back({.type = Token::Type::ArrayOpen});
|
||||
tokens.push_back({ .type = Token::Type::ArrayOpen });
|
||||
offset += 1;
|
||||
} else if (c == ']') {
|
||||
tokens.push_back({.type = Token::Type::ArrayClose});
|
||||
offset += 1;
|
||||
} else if (c == ',') {
|
||||
tokens.push_back({.type = Token::Type::Separator});
|
||||
tokens.push_back({ .type = Token::Type::Separator });
|
||||
offset += 1;
|
||||
} else if (c == '@') {
|
||||
tokens.push_back({.type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::AtDeclaration}});
|
||||
tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::AtDeclaration } });
|
||||
offset += 1;
|
||||
} else if (c == '=') {
|
||||
tokens.push_back({.type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Assignment}});
|
||||
tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Assignment } });
|
||||
offset += 1;
|
||||
} else if (c == ':') {
|
||||
tokens.push_back({.type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Inherit}});
|
||||
tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Inherit } });
|
||||
offset += 1;
|
||||
} else if (std::isalpha(c)) {
|
||||
std::string identifier = matchTillInvalid(&code[offset], [](char c) -> bool { return std::isalnum(c) || c == '_'; });
|
||||
@ -134,42 +134,44 @@ namespace hex::lang {
|
||||
// Check for reserved keywords
|
||||
|
||||
if (identifier == "struct")
|
||||
tokens.push_back({.type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Struct}});
|
||||
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Struct } });
|
||||
else if (identifier == "using")
|
||||
tokens.push_back({.type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Using}});
|
||||
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Using } });
|
||||
else if (identifier == "enum")
|
||||
tokens.push_back({.type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Enum}});
|
||||
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Enum } });
|
||||
else if (identifier == "bitfield")
|
||||
tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Bitfield } });
|
||||
|
||||
// Check for built-in types
|
||||
else if (identifier == "u8")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned8Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned8Bit } });
|
||||
else if (identifier == "s8")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed8Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed8Bit } });
|
||||
else if (identifier == "u16")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned16Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned16Bit } });
|
||||
else if (identifier == "s16")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed16Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed16Bit } });
|
||||
else if (identifier == "u32")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned32Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned32Bit } });
|
||||
else if (identifier == "s32")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed32Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed32Bit } });
|
||||
else if (identifier == "u64")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned64Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned64Bit } });
|
||||
else if (identifier == "s64")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed64Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed64Bit } });
|
||||
else if (identifier == "u128")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned128Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned128Bit } });
|
||||
else if (identifier == "s128")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed128Bit }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed128Bit } });
|
||||
else if (identifier == "float")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Float }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Float } });
|
||||
else if (identifier == "double")
|
||||
tokens.push_back({.type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Double }});
|
||||
tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Double } });
|
||||
|
||||
// If it's not a keyword and a builtin type, it has to be an identifier
|
||||
|
||||
else
|
||||
tokens.push_back({.type = Token::Type::Identifier, .identifierToken = { .identifier = identifier}});
|
||||
tokens.push_back({.type = Token::Type::Identifier, .identifierToken = { .identifier = identifier } });
|
||||
|
||||
offset += identifier.length();
|
||||
} else if (std::isdigit(c)) {
|
||||
@ -181,12 +183,12 @@ namespace hex::lang {
|
||||
if (!integer.has_value())
|
||||
return { ResultLexicalError, {}};
|
||||
|
||||
tokens.push_back({.type = Token::Type::Integer, .integerToken = { .integer = integer.value() }});
|
||||
tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = integer.value() } });
|
||||
offset += (end - &code[offset]);
|
||||
} else return { ResultLexicalError, {}};
|
||||
}
|
||||
|
||||
tokens.push_back({.type = Token::Type::EndOfProgram});
|
||||
tokens.push_back({ .type = Token::Type::EndOfProgram });
|
||||
|
||||
return { ResultSuccess, tokens };
|
||||
}
|
||||
|
@ -121,6 +121,26 @@ namespace hex::lang {
|
||||
return enumNode;
|
||||
}
|
||||
|
||||
ASTNode *parseBitField(TokenIter &curr) {
|
||||
const std::string &bitfieldName = curr[-2].identifierToken.identifier;
|
||||
std::vector<std::pair<std::string, size_t>> fields;
|
||||
|
||||
while (!tryConsume(curr, {Token::Type::ScopeClose})) {
|
||||
if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) {
|
||||
if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit)
|
||||
return nullptr;
|
||||
|
||||
fields.emplace_back(curr[-4].identifierToken.identifier, curr[-2].integerToken.integer);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
if (!tryConsume(curr, {Token::Type::EndOfExpression}))
|
||||
return nullptr;
|
||||
|
||||
return new ASTNodeBitField(bitfieldName, fields);
|
||||
}
|
||||
|
||||
ASTNode *parseScope(TokenIter &curr) {
|
||||
return new ASTNodeScope(parseTillToken(curr, Token::Type::ScopeClose));
|
||||
}
|
||||
@ -163,12 +183,21 @@ namespace hex::lang {
|
||||
}
|
||||
|
||||
program.push_back(structAst);
|
||||
} else if (curr[-3].keywordToken.keyword == Token::KeywordToken::Keyword::Bitfield) {
|
||||
auto bitfieldAst = parseBitField(curr);
|
||||
|
||||
if (bitfieldAst == nullptr) {
|
||||
for(auto &node : program) delete node;
|
||||
return { };
|
||||
}
|
||||
|
||||
program.push_back(bitfieldAst);
|
||||
}
|
||||
|
||||
return program;
|
||||
|
||||
} // Enum
|
||||
if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::ScopeOpen })) {
|
||||
else if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::ScopeOpen })) {
|
||||
if (curr[-5].keywordToken.keyword == Token::KeywordToken::Keyword::Enum) {
|
||||
auto enumAst = parseEnum(curr);
|
||||
|
||||
@ -181,7 +210,6 @@ namespace hex::lang {
|
||||
}
|
||||
|
||||
return program;
|
||||
|
||||
// Scope
|
||||
} else if (tryConsume(curr, { Token::Type::ScopeOpen })) {
|
||||
program.push_back(parseScope(curr));
|
||||
|
@ -61,6 +61,27 @@ namespace hex::lang {
|
||||
if (!constantNames.insert(name).second)
|
||||
return false;
|
||||
}
|
||||
case ASTNode::Type::Bitfield:
|
||||
{
|
||||
// Check for duplicate type name
|
||||
auto bitfieldNode = static_cast<ASTNodeBitField*>(node);
|
||||
if (!typeNames.insert(bitfieldNode->getName()).second)
|
||||
return false;
|
||||
|
||||
size_t bitfieldSize = 0;
|
||||
|
||||
// Check for duplicate constant names
|
||||
std::unordered_set<std::string> flagNames;
|
||||
for (const auto &[name, size] : bitfieldNode->getFields()) {
|
||||
if (!flagNames.insert(name).second)
|
||||
return false;
|
||||
|
||||
bitfieldSize += size;
|
||||
}
|
||||
|
||||
if (bitfieldSize > 64)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +109,18 @@ namespace hex {
|
||||
"}"
|
||||
);
|
||||
|
||||
DrawTitle("Bitfields");
|
||||
ImGui::TextWrapped(
|
||||
"To decode values that are stored in fields that don't follow the typical 8 bit alignment, bitfields can be used. "
|
||||
"The size of these fields get specified in numbers of bits.");
|
||||
DrawCodeSegment("bitfield", 70,
|
||||
"bitfield Permission {\n"
|
||||
" r : 1;\n"
|
||||
" w : 1;\n"
|
||||
" x : 1;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
DrawTitle("Enum");
|
||||
ImGui::TextWrapped(
|
||||
"If a value can only be a few specific values with special meaning, an enum can be used. "
|
||||
|
@ -14,7 +14,7 @@ namespace hex {
|
||||
static TextEditor::LanguageDefinition langDef;
|
||||
if (!initialized) {
|
||||
static const char* const keywords[] = {
|
||||
"using", "struct", "enum"
|
||||
"using", "struct", "enum", "bitfield"
|
||||
};
|
||||
for (auto& k : keywords)
|
||||
langDef.mKeywords.insert(k);
|
||||
@ -96,6 +96,10 @@ namespace hex {
|
||||
|
||||
if (ImGui::Begin("Pattern", &this->m_windowOpen, ImGuiWindowFlags_None)) {
|
||||
this->m_textEditor.Render("Pattern");
|
||||
|
||||
if (this->m_textEditor.IsTextChanged()) {
|
||||
this->parsePattern(this->m_textEditor.GetText().data());
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user