Created
December 15, 2022 19:51
-
-
Save blockspacer/6990ded4a66844d0a8fcdcd78a95be52 to your computer and use it in GitHub Desktop.
Parse arbitrary precision numbers with Boost spirit https://stackoverflow.com/questions/67253104/parse-arbitrary-precision-numbers-with-boost-spirit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <boost/spirit/include/qi.hpp> | |
#include <boost/spirit/include/phoenix.hpp> | |
#include <iomanip> | |
#include <llvm/ADT/APInt.h> | |
#include <llvm/ADT/SmallString.h> | |
namespace qi = boost::spirit::qi; | |
template <typename It> | |
struct IntLiteral : qi::grammar<It, llvm::APInt()> { | |
IntLiteral() : IntLiteral::base_type(_start) { | |
using namespace qi; | |
using Raw = std::uint64_t; | |
_start = no_case [ // case insensitive | |
("0x" >> uint_parser<Raw, 16>{} | | |
"0b" >> uint_parser<Raw, 2>{} | | |
&lit('0') >> uint_parser<Raw, 8>{} | | |
uint_parser<Raw, 10>{}) | |
// ignored for now: | |
>> _optsuffix | |
] [ _val = coerce_type(_1, _2) ]; | |
_optsuffix = no_case[_suffix] | attr(Suffix::signed_); | |
} | |
private: | |
enum class Suffix { | |
signed_ = 0, | |
unsigned_ = 1, | |
long_ = 2, | |
longlong_ = 4, | |
l_ = long_, | |
ll_ = longlong_, | |
ul_ = unsigned_ | l_, | |
ull_ = unsigned_ | ll_, | |
}; | |
struct suffix_sym : qi::symbols<char, Suffix> { | |
suffix_sym() { | |
this->add | |
("u", Suffix::unsigned_) | |
("l", Suffix::l_) | |
("ll", Suffix::ll_) | |
("ul", Suffix::ul_) ("lu", Suffix::ul_) | |
("ull", Suffix::ull_) ("llu", Suffix::ull_) | |
; | |
} | |
} _suffix; | |
struct converter_f { | |
template <typename T> static auto as(uint64_t raw) { | |
return llvm::APInt(CHAR_BIT * sizeof(T), raw, std::is_signed_v<T>); | |
} | |
llvm::APInt operator()(uint64_t raw, Suffix sfx) const { | |
switch (sfx) { | |
case Suffix::signed_: return as<signed>(raw); | |
case Suffix::unsigned_: return as<unsigned>(raw); | |
case Suffix::long_: return as<long>(raw); | |
case Suffix::longlong_: return as<long long>(raw); | |
case Suffix::ul_: return as<unsigned long>(raw); | |
case Suffix::ull_: return as<unsigned long long>(raw); | |
} | |
throw std::invalid_argument("sfx"); | |
} | |
}; | |
boost::phoenix::function<converter_f> coerce_type; | |
qi::rule<It, llvm::APInt()> _start; | |
qi::rule<It, Suffix()> _optsuffix; | |
}; | |
// see https://stackoverflow.com/questions/67253104/parse-arbitrary-precision-numbers-with-boost-spirit | |
void test() { | |
std::cout << " ---- " << __PRETTY_FUNCTION__ << "\n"; | |
using It = std::string::const_iterator; | |
IntLiteral<It> const parser {}; | |
for (std::string const input : { | |
"1234", | |
"1234u", | |
"0x12f34ULL", | |
"033ULL", | |
"0b101011l", | |
"33lu" | |
}) { | |
llvm::APInt value; | |
bool is_signed = true; // TODO signed? | |
bool formatAsCLiteral = false; // TODO formatAsCLiteral? | |
if (parse(input.begin(), input.end(), parser >> qi::eoi, value)) { | |
llvm::SmallString<40> smallString; | |
value.toString(smallString, 10, is_signed, formatAsCLiteral); // TODO signed? | |
std::cout << "Parsed " << std::quoted(input) << " -> " | |
<< ((std::string)(smallString)) | |
<< " bits:" << value.getBitWidth() << "\n"; | |
} else { | |
std::cout << "Failed to parse " << std::quoted(input) << "\n"; | |
} | |
} | |
} | |
int main() { | |
test(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment