|
|
@@ -29,9 +29,28 @@ void parser::parse_dN(sign s, int value) {
|
|
|
throw unexpected_token("Expected a number of sides", is_.tellg());
|
|
|
}
|
|
|
is_ >> dice_.of.back().sides;
|
|
|
+ if (std::strchr("kK", is_.peek())) {
|
|
|
+ is_.get();
|
|
|
+ parse_keep(is_.get());
|
|
|
+ }
|
|
|
parse_impl(sign::ZERO);
|
|
|
}
|
|
|
|
|
|
+void parser::parse_keep(char token) {
|
|
|
+ switch (token) {
|
|
|
+ case 'h':
|
|
|
+ case 'H':
|
|
|
+ dice_.of.back().keep = {keep::Highest, read()};
|
|
|
+ break;
|
|
|
+ case 'l':
|
|
|
+ case 'L':
|
|
|
+ dice_.of.back().keep = {keep::Lowest, read()};
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw unexpected_token("Expected high/low in keep expression", is_.tellg());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void parser::parse_const(sign s, int value) {
|
|
|
if (value) { // Zero is not a modifier we care about
|
|
|
dice_.modifier.push_back({s, std::abs(value)});
|
|
|
@@ -55,16 +74,20 @@ void parser::parse_dc(char token) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void parser::parse_impl(sign s) {
|
|
|
- advance_over_whitespace(is_);
|
|
|
+int parser::read(int value, bool error_on_eof) {
|
|
|
// By defaulting this to zero, we can write a more elegant handling of
|
|
|
// expressions like 1d4+1d6+5+1
|
|
|
- int value = 0;
|
|
|
if (isnumber(is_.peek())) {
|
|
|
is_ >> value;
|
|
|
- } else if (is_.peek() == EOF && s != sign::ZERO) {
|
|
|
+ } else if (is_.peek() == EOF && error_on_eof) {
|
|
|
throw unexpected_token("Unexpected EOF while parsing", -1);
|
|
|
}
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
+void parser::parse_impl(sign s) {
|
|
|
+ advance_over_whitespace(is_);
|
|
|
+ int const value = read(0, s != sign::ZERO);
|
|
|
advance_over_whitespace(is_);
|
|
|
switch (is_.peek()) {
|
|
|
case 'd':
|
|
|
@@ -89,9 +112,8 @@ void parser::parse_impl(sign s) {
|
|
|
|
|
|
dice parser::parse() {
|
|
|
dice_ = {};
|
|
|
- int value{1};
|
|
|
advance_over_whitespace(is_);
|
|
|
- if (isnumber(is_.peek())) { is_ >> value; }
|
|
|
+ int const value = read(1, false);
|
|
|
advance_over_whitespace(is_);
|
|
|
|
|
|
switch (is_.peek()) {
|