From c2bcbfb1e038e6be511b75936d9951171394dff9 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 2 Feb 2022 17:12:19 +0100 Subject: [PATCH] pattern: std::from_chars is not widely supported and doesn't support u128... --- .../source/pattern_language/lexer.cpp | 60 ++++++++++--------- .../test_patterns/test_pattern_enums.hpp | 8 +-- .../test_patterns/test_pattern_math.hpp | 2 +- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/lib/libimhex/source/pattern_language/lexer.cpp b/lib/libimhex/source/pattern_language/lexer.cpp index 8b7f09b91..b5004d094 100644 --- a/lib/libimhex/source/pattern_language/lexer.cpp +++ b/lib/libimhex/source/pattern_language/lexer.cpp @@ -38,11 +38,14 @@ namespace hex::pl { } std::optional lexIntegerLiteral(std::string_view string) { + bool hasFloatSuffix = string.ends_with('D') || string.ends_with('F') || string.ends_with('d') || string.ends_with('f'); + bool isFloat = std::count(string.begin(), string.end(), '.') == 1 || + !string.starts_with("0x") && hasFloatSuffix; - if (std::count(string.begin(), string.end(), '.') == 1) { + if (isFloat) { // Parse double char suffix = 0x00; - if (string.ends_with('D') || string.ends_with('F') || string.ends_with('d') || string.ends_with('f')) { + if (hasFloatSuffix) { suffix = string.back(); string = string.substr(0, string.length() - 1); } @@ -63,45 +66,46 @@ namespace hex::pl { } } } else { - bool unsignedNumber = false; + bool isUnsigned = false; if (string.ends_with('U') || string.ends_with('u')) { - unsignedNumber = true; - string = string.substr(0, string.length() - 1); + isUnsigned = true; + string = string.substr(0, string.length() - 1); } - i128 value; + u8 prefixOffset = 0; + u8 base = 10; + if (string.starts_with("0x") || string.starts_with("0X")) { // Parse hexadecimal - - auto [p, error] = std::from_chars(string.begin() + 2, string.end(), value, 16); - - if (error == std::errc::invalid_argument || p != string.end()) - return std::nullopt; + prefixOffset = 2; + base = 16; } else if (string.starts_with("0o") || string.starts_with("0O")) { // Parse octal - - auto [p, error] = std::from_chars(string.begin() + 2, string.end(), value, 8); - - if (error == std::errc::invalid_argument || p != string.end()) - return std::nullopt; + prefixOffset = 2; + base = 8; } else if (string.starts_with("0b") || string.starts_with("0B")) { // Parse binary - - auto [p, error] = std::from_chars(string.begin() + 2, string.end(), value, 2); - - if (error == std::errc::invalid_argument || p != string.end()) - return std::nullopt; + prefixOffset = 2; + base = 2; } else { // Parse decimal - - auto [p, error] = std::from_chars(string.begin(), string.end(), value, 10); - - if (error == std::errc::invalid_argument || p != string.end()) - return std::nullopt; + prefixOffset = 0; + base = 10; } - if (unsignedNumber) - return u128(value); + u128 value = 0x00; + for (char c : string.substr(prefixOffset)) { + value *= base; + value += [&] { + if (c >= '0' && c <= '9') return c - '0'; + else if (c >= 'A' && c <= 'F') return 0xA + (c - 'A'); + else if (c >= 'a' && c <= 'f') return 0xA + (c - 'a'); + else return 0x00; + }(); + } + + if (isUnsigned) + return value; else return i128(value); } diff --git a/tests/pattern_language/include/test_patterns/test_pattern_enums.hpp b/tests/pattern_language/include/test_patterns/test_pattern_enums.hpp index 110019cb1..cb9eb303e 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_enums.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_enums.hpp @@ -9,10 +9,10 @@ namespace hex::test { TestPatternEnums() : TestPattern("Enums") { auto testEnum = create("TestEnum", "testEnum", 0x08, sizeof(u32)); testEnum->setEnumValues({ - {u128(0x0000), "A"}, - { i128(0x0C), "B"}, - { u128(0x0D), "C"}, - { u128(0x0E), "D"}, + {u128(0x00), "A"}, + { i128(0x0C), "B"}, + { u128(0x0D), "C"}, + { u128(0x0E), "D"}, }); testEnum->setEndian(std::endian::big); diff --git a/tests/pattern_language/include/test_patterns/test_pattern_math.hpp b/tests/pattern_language/include/test_patterns/test_pattern_math.hpp index 8cb0b54be..e365d2b0f 100644 --- a/tests/pattern_language/include/test_patterns/test_pattern_math.hpp +++ b/tests/pattern_language/include/test_patterns/test_pattern_math.hpp @@ -31,7 +31,7 @@ namespace hex::test { std::assert(0xFF00FF | 0x00AA00 == 0xFFAAFF, "| operator error"); std::assert(0xFFFFFF & 0x00FF00 == 0x00FF00, "& operator error"); std::assert(0xFFFFFF ^ 0x00AA00 == 0xFF55FF, "^ operator error"); - std::assert(~0x00 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "~ operator error"); + std::assert(~0x00U == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, "~ operator error"); std::assert(0xAA >> 4 == 0x0A, ">> operator error"); std::assert(0xAA << 4 == 0xAA0, "<< operator error");