소스 검색

Improve parser code.

Sam Jaffe 4 년 전
부모
커밋
7071774291
4개의 변경된 파일50개의 추가작업 그리고 44개의 파일을 삭제
  1. 2 2
      dice-roll.xcodeproj/project.pbxproj
  2. 12 5
      include/dice-roll/parser.h
  3. 2 34
      src/io.cxx
  4. 34 3
      src/parser.cxx

+ 2 - 2
dice-roll.xcodeproj/project.pbxproj

@@ -619,7 +619,7 @@
 					"$(BUILT_PRODUCTS_DIR)/usr/local/include",
 					/opt/local/include,
 				);
-				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MACOSX_DEPLOYMENT_TARGET = 10.15;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				ONLY_ACTIVE_ARCH = YES;
@@ -678,7 +678,7 @@
 					"$(BUILT_PRODUCTS_DIR)/usr/local/include",
 					/opt/local/include,
 				);
-				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MACOSX_DEPLOYMENT_TARGET = 10.15;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
 				SDKROOT = macosx;

+ 12 - 5
include/dice-roll/parser.h

@@ -14,7 +14,17 @@
 
 namespace dice {
 
-struct parser {
+class parser {
+private:
+  std::istream & in;
+  dice d;
+  
+public:
+  parser(std::istream & in) : in(in) {}
+  
+  dice parse();
+  
+private:
   /**
    * Main dispatch function for parsing a dice roll.
    * @param s The current +/- sign attached to the parse sequence. s is ZERO
@@ -29,7 +39,7 @@ struct parser {
    * 5) ZERO, +2d8
    * 6) PLUS, 2d8
    */
-  void parse(sign s);
+  void parse_impl(sign s);
   /**
    * @sideeffect This function advances the input stream over a single numeric
    * token. This token represents the number of sides in the die roll.
@@ -52,9 +62,6 @@ struct parser {
    * Domain: value >= 0
    */
   void parse_const(sign s, int value);
-
-  std::istream & in;
-  dice & d;
 };
 
 }

+ 2 - 34
src/io.cxx

@@ -13,13 +13,6 @@
 #include "dice-roll/exception.h"
 #include "dice-roll/parser.h"
 
-static void advance_over_whitespace(std::istream & in, char const * also = "") {
-  if (strchr(also, in.peek())) { in.get(); }
-  while (isspace(in.peek())) {
-    in.get();
-  }
-}
-
 namespace dice {
 
 std::ostream & operator<<(std::ostream & out, dice const & d) {
@@ -35,38 +28,13 @@ std::ostream & operator<<(std::ostream & out, dice const & d) {
 }
 
 std::istream & operator>>(std::istream & in, dice & d) {
-  int value{1};
-  advance_over_whitespace(in);
-  if (isnumber(in.peek())) { in >> value; }
-  advance_over_whitespace(in);
-  switch (in.peek()) {
-  case 'd':
-  case 'D':
-    parser{in, d}.parse(ZERO);
-    d.of.front().num = value;
-    break;
-  case '{':
-    in.get();
-    d.num = value;
-    parser{in, d}.parse(ZERO);
-    if (in.get() != '}') {
-      throw unexpected_token("Expected closing '}' in repeated roll",
-                             in.tellg());
-    }
-    break;
-  case EOF:
-    throw unexpected_token("No dice in expression", in.tellg());
-  default:
-    throw unexpected_token("Unexpected token", in.tellg());
-  }
+  d = parser(in).parse();
   return in;
 }
 
 dice from_string(std::string const & str) {
   std::stringstream ss(str);
-  dice d;
-  ss >> d;
-  return d;
+  return parser(ss).parse();
 }
 
 }

+ 34 - 3
src/parser.cxx

@@ -29,7 +29,7 @@ void parser::parse_dN(sign s, int value) {
     throw unexpected_token("Expected a number of sides", in.tellg());
   }
   in >> d.of.back().sides;
-  parse(ZERO);
+  parse_impl(ZERO);
 }
 
 void parser::parse_const(sign s, int value) {
@@ -38,7 +38,7 @@ void parser::parse_const(sign s, int value) {
   }
 }
 
-void parser::parse(sign s) {
+void parser::parse_impl(sign s) {
   advance_over_whitespace(in);
   // By defaulting this to zero, we can write a more elegant handling of
   // expressions like 1d4+1d6+5+1
@@ -58,7 +58,7 @@ void parser::parse(sign s) {
     // Handle 5+... cases
     parse_const(s, value);
     // Add another token
-    parse((in.get() == '+') ? PLUS : MINUS);
+    parse_impl((in.get() == '+') ? PLUS : MINUS);
     break;
   default:
     parse_const(s, value);
@@ -66,4 +66,35 @@ void parser::parse(sign s) {
   }
 }
 
+dice parser::parse() {
+  d = {};
+  int value{1};
+  advance_over_whitespace(in);
+  if (isnumber(in.peek())) { in >> value; }
+  advance_over_whitespace(in);
+  
+  switch (in.peek()) {
+  case 'd':
+  case 'D':
+    parse_impl(ZERO);
+    d.of.front().num = value;
+    break;
+  case '{':
+    in.get();
+    d.num = value;
+    parse_impl(ZERO);
+    if (in.get() != '}') {
+      throw unexpected_token("Expected closing '}' in repeated roll",
+                             in.tellg());
+    }
+    break;
+  case EOF:
+    throw unexpected_token("No dice in expression", in.tellg());
+  default:
+    throw unexpected_token("Unexpected token", in.tellg());
+  }
+
+  return d;
+}
+
 }