Calculator  Step 1
Public Member Functions | Private Member Functions | Private Attributes | List of all members
parser Class Reference

#include <parse.hpp>

Public Member Functions

 parser (std::istream &input)
 
bool get_expr (double &result)
 

Private Member Functions

std::string charify (char c)
 
bool get_number (double &result)
 
bool get_primary (double &result)
 
bool get_mult_expr (double &result)
 

Private Attributes

std::istream & input_
 
std::ctype< char > const & ctype_
 

Detailed Description

Parser class template.

Definition at line 17 of file parse.hpp.

Constructor & Destructor Documentation

parser::parser ( std::istream &  input)

Constructor. Save the input stream.

Parameters
inputThe input stream

Definition at line 6 of file parse.cpp.

7 : input_(input),
8  ctype_(std::use_facet<std::ctype<char>>(input.getloc()))
9 {}
std::istream & input_
Definition: parse.hpp:55
std::ctype< char > const & ctype_
Definition: parse.hpp:56

Member Function Documentation

std::string parser::charify ( char  c)
private

Convert a characer to a readable form.

Parameters
cThe character
Returns
A C++-style character literal that ensures c is readable.

Definition at line 11 of file parse.cpp.

Referenced by get_number(), and get_primary().

12 {
13  if (c == '\a') return R"('\a')";
14  if (c == '\b') return R"('\b')";
15  if (c == '\f') return R"('\f')";
16  if (c == '\n') return R"('\n')";
17  if (c == '\r') return R"('\r')";
18  if (c == '\t') return R"('\t')";
19  if (c == '\v') return R"('\v')";
20  if (c == '\'') return R"('\'')";
21  if (c == '\\') return R"('\\')";
22 
23  if (isprint(c))
24  return std::string{"\'"} + std::string(1,c) + "\'";
25  else {
26  std::ostringstream stream{};
27  stream << "'\\x" << std::hex;
28  stream.fill('0');
29  stream.width(2);
30  stream << (std::char_traits<char>::to_int_type(c) & 0xFF) << '\'';
31  return stream.str();
32  }
33 }
bool parser::get_expr ( double &  result)

Read one expression and store the result in result.

Parameters
resultWhere to store the result of the expression.
Returns
true to continue or false to end the loop
Exceptions
parse_errorfor various syntax and other errors

Definition at line 110 of file parse.cpp.

References get_mult_expr(), and input_.

Referenced by get_primary().

111 {
112  if (not get_mult_expr(result))
113  return false;
114  char c{};
115  while (input_ >> c) {
116  if (c != '+' and c != '-') {
117  input_.unget();
118  return true;
119  } else {
120  double right{};
121  if (not get_mult_expr(right))
122  throw parse_error{"syntax error: unterminated expression. Expected a multiplicative-exprssion after " + std::string(c,1)};
123  if (c == '+')
124  result += right;
125  else
126  result -= right;
127  }
128  }
129  return true;
130 }
std::istream & input_
Definition: parse.hpp:55
bool get_mult_expr(double &result)
Definition: parse.cpp:135
bool parser::get_mult_expr ( double &  result)
private

Parse a multiplicative expression.

Parameters
resultStore the number here
Returns
true to continue parsing or false to stop (end of file or error)

Definition at line 135 of file parse.cpp.

References get_primary(), and input_.

Referenced by get_expr().

136 {
137  if (not get_primary(result))
138  return false;
139  char c{};
140  while (input_ >> c) {
141  if (c != '*' and c != '/') {
142  input_.unget();
143  return true;
144  } else {
145  double right{};
146  if (not get_primary(right))
147  throw parse_error{"syntax error: unterminated expression. Expected a primary after " + std::string(c,1)};
148  if (c == '*')
149  result *= right;
150  else if (right == 0.0)
151  throw parse_error{"division by zero"};
152  else
153  result /= right;
154  }
155  }
156  return true;
157 }
bool get_primary(double &result)
Definition: parse.cpp:162
std::istream & input_
Definition: parse.hpp:55
bool parser::get_number ( double &  result)
private

Parse a number.

Parameters
resultStore the number here
Returns
true to continue parsing or false to stop (end of file or error)

Definition at line 38 of file parse.cpp.

References charify(), and input_.

Referenced by get_primary().

39 {
40  std::string token{};
41  char c{};
42  if (not input_.get(c))
43  return false;
44  if (c == '+' or c == '-') {
45  token += c;
46  if (not input_.get(c))
47  throw parse_error{"unterminated number: expected a digit after the sign"};
48  }
49  if (c < '0' or c > '9') {
50  input_.unget();
51  throw parse_error{"syntax error: expected digit, got " + charify(c)};
52  }
53  while (c >= '0' and c <= '9') {
54  token += c;
55  if (not input_.get(c)) {
56  std::istringstream tmp{std::move(token)};
57  // If the value overflows, return false.
58  return (tmp >> result);
59  }
60  }
61  if (c == '.') {
62  token += c;
63  if (not input_.get(c))
64  throw parse_error{"unterminated number: expected digit after the decimal point"};
65  if (c < '0' or c > '9') {
66  input_.unget();
67  throw parse_error{"syntax error: expected digit after decimal point, got " + charify(c)};
68  }
69  while (c >= '0' and c <= '9') {
70  token += c;
71  if (not input_.get(c)) {
72  std::istringstream tmp{std::move(token)};
73  // If the value overflows or is otherwise invalid, return false.
74  return (tmp >> result);
75  }
76  }
77  }
78  if (c == 'e' or c == 'E') {
79  token += c;
80  if (not input_.get(c))
81  throw parse_error{"unterminated number: expected digit in the exponent"};
82  if (c == '-' or c == '+') {
83  token += c;
84  if (not input_.get(c))
85  throw parse_error{"unterminated number: expected digit after sign in the exponent"};
86  }
87  if (c < '0' or c > '9') {
88  input_.unget();
89  throw parse_error{"syntax error: expected digit in the exponent, got " + charify(c)};
90  }
91  while (c >= '0' and c <= '9') {
92  token += c;
93  if (not input_.get(c)) {
94  std::istringstream tmp{std::move(token)};
95  // If the value overflows or is otherwise invalid, return false.
96  return (tmp >> result);
97  }
98  }
99  }
100  input_.unget();
101 
102  std::istringstream tmp{std::move(token)};
103  // If the value overflows or is otherwise invalid, return false.
104  return (tmp >> result);
105 }
std::string charify(char c)
Definition: parse.cpp:11
std::istream & input_
Definition: parse.hpp:55
bool parser::get_primary ( double &  result)
private

Parse a primary expression. A primary is a parenthesized expression or a numeric literal.

Parameters
resultStore the number here
Returns
true to continue parsing or false to stop (end of file or error)

Definition at line 162 of file parse.cpp.

References charify(), get_expr(), get_number(), and input_.

Referenced by get_mult_expr().

163 {
164  char c{};
165  if (not (input_ >> c))
166  // Can't read one character, so must be end-of-file
167  return false;
168  else if (c == '(') {
169  if (not get_expr(result))
170  return false;
171  if (not (input_ >> c))
172  throw parse_error{"syntax error: EOF when expecting ')'"};
173  else if (c != ')')
174  throw parse_error{"syntax error: expected ')', but got " + charify(c)};
175  else
176  return true;
177  } else {
178  input_.unget();
179  return get_number(result);
180  }
181 }
std::string charify(char c)
Definition: parse.cpp:11
bool get_number(double &result)
Definition: parse.cpp:38
bool get_expr(double &result)
Definition: parse.cpp:110
std::istream & input_
Definition: parse.hpp:55

Member Data Documentation

std::ctype<char> const& parser::ctype_
private

Definition at line 56 of file parse.hpp.

std::istream& parser::input_
private

Definition at line 55 of file parse.hpp.

Referenced by get_expr(), get_mult_expr(), get_number(), and get_primary().


The documentation for this class was generated from the following files: