Skip to content

Instantly share code, notes, and snippets.

@blockspacer
Created December 15, 2022 19:51
Show Gist options
  • Save blockspacer/6990ded4a66844d0a8fcdcd78a95be52 to your computer and use it in GitHub Desktop.
Save blockspacer/6990ded4a66844d0a8fcdcd78a95be52 to your computer and use it in GitHub Desktop.
#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