main.cxx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // main.cpp
  3. // stateful_dice
  4. //
  5. // Created by Sam Jaffe on 12/18/18.
  6. // Copyright © 2018 Sam Jaffe. All rights reserved.
  7. //
  8. #include <fstream>
  9. #include <iostream>
  10. #include <map>
  11. #include <regex>
  12. #include "dice-roll/exception.h"
  13. void usage() {
  14. std::cout << "'help' : Print this message\n";
  15. std::cout << "'A := Dice' : Create a substitution pattern\n";
  16. std::cout << "'1d6+$Dex' : Roll 1d6 plus whatever value subs for 'Dex'\n";
  17. }
  18. void print_binding_os(std::pair<const std::string, std::string> const & pair,
  19. std::ostream & os) {
  20. os << pair.first;
  21. if (pair.second == "")
  22. os << " is not defined\n";
  23. else
  24. os << " := " << pair.second << "\n";
  25. }
  26. void print_binding(std::pair<const std::string, std::string> const & pair) {
  27. print_binding_os(pair, std::cout);
  28. }
  29. class evaluator {
  30. public:
  31. evaluator(std::string const & path = "") {
  32. if (!path.empty()) { load(path); }
  33. }
  34. void operator()(std::string const & str);
  35. private:
  36. using binding_t = std::map<std::string, std::string>;
  37. bool regex_search(char const * regex) {
  38. return std::regex_match(curr, match, std::regex(regex));
  39. }
  40. binding_t::value_type find_or(std::string const & key) const {
  41. auto it = bindings.find(key);
  42. return it == bindings.cend() ? binding_t::value_type(key, "") : *it;
  43. }
  44. void save(std::string const & file) const {
  45. using namespace std::placeholders;
  46. std::ofstream out(file);
  47. std::for_each(bindings.begin(), bindings.end(),
  48. std::bind(&print_binding_os, _1, std::ref(out)));
  49. }
  50. void load(std::string const & file) {
  51. std::ifstream in(file);
  52. while (std::getline(in, curr)) {
  53. if (regex_search(R"(^(\w+)\s*:=\s*(.*)$)")) {
  54. bindings[match[1]] = match[2];
  55. }
  56. }
  57. }
  58. private:
  59. std::string curr;
  60. std::smatch match;
  61. binding_t bindings;
  62. };
  63. void evaluator::operator()(std::string const & str) {
  64. curr = str;
  65. try {
  66. if (regex_search(R"(help|\?)")) {
  67. usage();
  68. } else if (regex_search(R"(^(\w+)\s*:=\s*(.*)$)")) {
  69. bindings[match[1]] = match[2];
  70. } else if (regex_search(R"(^show (\*|all))")) {
  71. std::for_each(bindings.begin(), bindings.end(), &print_binding);
  72. } else if (regex_search(R"(^show (\w+))")) {
  73. print_binding(find_or(match[1]));
  74. } else if (regex_search(R"(^unset (\*|all))")) {
  75. bindings.clear();
  76. } else if (regex_search(R"(^unset (\w+))")) {
  77. bindings.erase(match[1]);
  78. } else if (regex_search(R"(^save (.+))")) {
  79. save(match[1]);
  80. } else if (regex_search(R"(^load new (.+))")) {
  81. bindings.clear();
  82. load(match[1]);
  83. } else if (regex_search(R"(^load (.+))")) {
  84. load(match[1]);
  85. } else {
  86. while (regex_search(R"(.*(\$\w+).*)")) {
  87. curr.replace(match[1].first, match[1].second,
  88. find_or(match[1].str().substr(1)).second);
  89. }
  90. auto d = dice::from_string(curr);
  91. auto rs = dice::roller()(d);
  92. std::cout << std::make_pair(d, rs) << '\n';
  93. }
  94. } catch (dice::unexpected_token const & ut) {
  95. std::cerr << "Error in roll: '" << curr << "': " << ut.what() << "\n";
  96. std::cerr << " " << ut.pointer(str.size() + 1) << std::endl;
  97. }
  98. }
  99. int main(int argc, const char * argv[]) {
  100. std::string line;
  101. std::cout << "> ";
  102. evaluator eval(argc > 1 ? argv[1] : "");
  103. while (std::getline(std::cin, line)) {
  104. eval(line);
  105. std::cout << "> ";
  106. }
  107. return 0;
  108. }