Calculator Step 6

- Main Page
- Classes
- Files

- Class List
- Class Index
- Class Hierarchy
- Class Members

Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
parser Class Reference

`#include <parse.hpp>`

## Public Types
enum | kind : int { eof, identifier, integer, floating_point, string, plus ='+', minus ='-', times ='*', slash ='/', lparen = '(', rparen =')', equal ='=', comma =',' }

## Public Member Functions
| parser (std::istream &input)
bool | get_statement (std::ostream &output)

## Private Member Functions
std::string | charify (char c)
bool | get_float (std::string const &token, node &result)
bool | get_integer (std::string const &token, node &result)
bool | get_expr (node &result)
bool | get_add_expr (node &result)
bool | get_mul_expr (node &result)
bool | get_primary (node &result)
bool | get_unary (node &result)
void | get_definition (std::string &name, identifier_list &parameters, node &definition)
kind | get_token (std::string &token)
void | get_identifier (std::string &identifier)
void | get_expr_list (node_list &result)
template<class OutputIterator >
OutputIterator | get_namelist (OutputIterator output)
void | get_escape (std::string &str)
void | get_string (std::string &result, char delimiter)
void | push_back (std::string const &token, kind k)
bool | isalpha (char c) const
bool | isalnum (char c) const
bool | isdigit (char c) const
bool | isprint (char c) const

## Private Attributes
std::istream & | input_
| Share the input stream. More...
std::ctype< char > const & | ctype_
| Cache the ctype facet for checking character categories. More...
std::string | token_
| One token push-back. More...
kind | kind_
| The kind of token that was pushed back. More...

## Detailed Description

Parser class template. The parser reads tokens from an input stream. A token can be a keyword, numeric literal, identifier, or symbol (operator or punctuator). Symbols can have multiple characters (e.g., :=).

Because the recursive-descent parser can examine too many tokens from the input stream, it keeps a push-back token. Once the parser knows it has gone too far, it pushes back the most recently read token. The next call to get_token() retrieves the pushed-back token.

Only one push-back is available, which limits the complexity of the syntax.

Definition at line 26 of file parse.hpp.

## Member Enumeration Documentation

enum parser::kind : int

Token kind. Declare a name for each single-character token, to ensure the enumerated type can represent any operator or punctuator character.

Enumerator
eof |
identifier |
integer |
floating_point |
string |
plus |
minus |
times |
slash |
lparen |
rparen |
equal |
comma |

Definition at line 32 of file parse.hpp.

32 : int { eof, identifier, integer, floating_point, string,
33 plus='+', minus='-', times='*', slash='/', lparen = '(', rparen=')', equal='=',
34 comma=','};
parser::slash
Definition: parse.hpp:33
parser::comma
Definition: parse.hpp:34
parser::times
Definition: parse.hpp:33
parser::lparen
Definition: parse.hpp:33
parser::rparen
Definition: parse.hpp:33
parser::plus
Definition: parse.hpp:33
parser::integer
Definition: parse.hpp:32
parser::minus
Definition: parse.hpp:33
parser::floating_point
Definition: parse.hpp:32
parser::equal
Definition: parse.hpp:33
parser::eof
Definition: parse.hpp:32
parser::string
Definition: parse.hpp:32
parser::identifier
Definition: parse.hpp:32

## Constructor & Destructor Documentation

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

Constructor. Save the `input` stream.

Parameters

  input | The input stream

Definition at line 10 of file parse.cpp.

11 : input_(input),
12 ctype_(std::use_facet<std::ctype<char> >(input.getloc())),
13 token_(),
14 kind_()
15 {}
parser::token_
std::string token_
One token push-back.
Definition: parse.hpp:204
parser::input_
std::istream & input_
Share the input stream.
Definition: parse.hpp:202
parser::kind_
kind kind_
The kind of token that was pushed back.
Definition: parse.hpp:205
parser::ctype_
std::ctype< char > const & ctype_
Cache the ctype facet for checking character categories.
Definition: parse.hpp:203

## Member Function Documentation

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

Convert a characer to a readable form.

Parameters

  c | The character

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

Definition at line 17 of file parse.cpp.

References isprint().

Referenced by get_identifier(), and get_token().

18 {
19 if (c == '\a') return R"('\a')";
20 if (c == '\b') return R"('\b')";
21 if (c == '\f') return R"('\f')";
22 if (c == '\n') return R"('\n')";
23 if (c == '\r') return R"('\r')";
24 if (c == '\t') return R"('\t')";
25 if (c == '\v') return R"('\v')";
26 if (c == '\'') return R"('\'')";
27 if (c == '\\') return R"('\\')";
28
29 if (isprint(c))
30 return std::string{"\'"} + std::string(1,c) + "\'";
31 else {
32 std::ostringstream stream{};
33 stream << "'\\x" << std::hex;
34 stream.fill('0');
35 stream.width(2);
36 stream << (std::char_traits<char>::to_int_type(c) & 0xFF) << '\'';
37 return stream.str();
38 }
39 }
parser::isprint
bool isprint(char c) const
Definition: parse.hpp:200

bool parser::get_add_expr | ( | node & | result | ) |
| private

Parse an addition expression

    ADD_EXPR ::= MUL_EXPR | ADD_EXPR + MUL_EXPR | ADD_EXPR - MUL_EXPR

Parameters

  result | Store the result here

Returns
  true to continue parsing or false to stop (end of file or error)

Definition at line 312 of file parse.cpp.

References get_mul_expr(), get_token(), and push_back().

Referenced by get_expr().

313 {
314 if (not get_mul_expr(result))
315 return false;
316 std::string token{};
317 while (kind k = get_token(token)) {
318 if (k != '+' and k != '-') {
319 push_back(token, k);
320 return true;
321 } else {
322 node right{};
323 if (not get_mul_expr(right))
324 throw syntax_error{"unterminated expression. Expected a multiplicative-expression after " + token};
325 result = node(result, k, right);
326 }
327 }
328 return true;
329 }
node
Definition: node.hpp:28
parser::push_back
void push_back(std::string const &token, kind k)
Definition: parse.cpp:121
syntax_error
Definition: calc_error.hpp:24
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::kind
kind
Definition: parse.hpp:32
parser::get_mul_expr
bool get_mul_expr(node &result)
Definition: parse.cpp:331

void parser::get_definition | ( | std::string & | name,
|  | identifier_list & | parameters,
|  | node & | definition
| ) |  |
| private

Parse a function or variable definition A variable is just like a function that takes no parameters.

    DEFINITION ::= DEF IDENTIFIER OPT_PARAMETERS '=' EXPR
    OPT_PARAMETERS ::= emtpy | '(' OPT_IDENTIFIER_LIST ')'
    OPT_IDENTIFIER_LIST ::=  empty | IDENTIFIER_LIST
    IDENTIFIER_LIST ::= IDENTIFIER | IDENTIFIER_LIST ',' IDENTIFIER

Parameters

  [out] | name | Store the variable or function name here
  [out] | parameters | Store the list of parameter names here
  [out] | definition | Store the definition expression here

Definition at line 241 of file parse.cpp.

References get_expr(), get_namelist(), get_token(), and identifier.

Referenced by get_statement().

242 {
243 // Define a variable.
244 kind k = get_token(name);
245 if (k != identifier)
246 throw syntax_error{"expected IDENTIFIER, got " + name};
247
248 std::string token{};
249 k = get_token(token);
250 if (k == '(') {
251 get_namelist(std::back_inserter(parameters));
252 k = get_token(token);
253 }
254
255 if (k != '=')
256 throw syntax_error{"expected = in definition, got " + token};
257
258 if (not get_expr(definition))
259 throw syntax_error{"expected exprssion in assignment"};
260 }
parser::get_expr
bool get_expr(node &result)
Definition: parse.cpp:307
syntax_error
Definition: calc_error.hpp:24
parser::get_namelist
OutputIterator get_namelist(OutputIterator output)
Definition: parse.hpp:216
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::kind
kind
Definition: parse.hpp:32
parser::identifier
Definition: parse.hpp:32

void parser::get_escape | ( | std::string & | str | ) |
| private

Interpret a backslash escape sequence. The caller must have read the backslash already.

Parameters

  [out] | str | Write the string equivalent of the escape sequence at the end of this string

Definition at line 41 of file parse.cpp.

References ctype_, and input_.

Referenced by get_string().

42 {
43 char c;
44 if (not input_.get(c))
45 throw syntax_error{"incomplete escape"};
46 if (c == '\n')
47 return;
48
49 if (c == 'a')
50 str += '\a';
51 else if (c == 'b')
52 str += '\b';
53 else if (c == 'n')
54 str += '\n';
55 else if (c == 'f')
56 str += '\f';
57 else if (c == 'r')
58 str += '\r';
59 else if (c == 't')
60 str += '\t';
61 else if (c == 'v')
62 str += '\v';
63 else if (c == 'x') {
64 // hexadecimal sequence
65 std::string digits{};
66 while(input_.get(c) and ctype_.is(ctype_.xdigit, c))
67 digits += c;
68 if (input_)
69 input_.unget();
70 unsigned long value{std::stoul(digits, nullptr, 16)};
71 str += static_cast<char>(static_cast<unsigned char>(value));
72 } else if (c >= '0' and c <= '7') {
73 // octal sequence
74 std::string digits{};
75 for (int i = 0; i < 3 and input_.get(c) and c >= '0' and c <= '7'; ++i)
76 digits += c;
77 if (input_ or c < '0' or c > '7')
78 input_.unget();
79 int value{std::stoi(digits, nullptr, 8)};
80 str += static_cast<char>(static_cast<unsigned char>(value));
81 } else {
82 str += c;
83 }
84 }
syntax_error
Definition: calc_error.hpp:24
parser::input_
std::istream & input_
Share the input stream.
Definition: parse.hpp:202
parser::ctype_
std::ctype< char > const & ctype_
Cache the ctype facet for checking character categories.
Definition: parse.hpp:203

bool parser::get_expr | ( | node & | result | ) |
| private

Parse an expression

Parameters

  result | Store the result here

Returns
  true to continue parsing or false to stop (end of file or error)

Definition at line 307 of file parse.cpp.

References get_add_expr().

Referenced by get_definition(), get_expr_list(), get_primary(), and get_statement().

308 {
309 return get_add_expr(result);
310 }
parser::get_add_expr
bool get_add_expr(node &result)
Definition: parse.cpp:312

void parser::get_expr_list | ( | node_list & | result | ) |
| private

Parse a comma-separated expression list.

Parameters

  [out] | result | Store the result here

Definition at line 371 of file parse.cpp.

References get_expr(), get_token(), and push_back().

Referenced by get_primary().

372 {
373 result.clear();
374 std::string token{};
375 while (kind k = get_token(token)) {
376 if (k == ')')
377 return;
378 push_back(token, k);
379 node expr{};
380 if (not get_expr(expr))
381 throw syntax_error{"unexpected end of line in function argument"};
382 result.push_back(expr);
383 k = get_token(token);
384 if (k == ')')
385 return;
386 else if (k != ',')
387 throw syntax_error{"expected comma in argument list, got " + token};
388 }
389 throw syntax_error{"unexpected end of line in function argument list"};
390 }
parser::get_expr
bool get_expr(node &result)
Definition: parse.cpp:307
node
Definition: node.hpp:28
parser::push_back
void push_back(std::string const &token, kind k)
Definition: parse.cpp:121
syntax_error
Definition: calc_error.hpp:24
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::kind
kind
Definition: parse.hpp:32

bool parser::get_float | ( | std::string const & | token,
|  | node & | result
| ) |  |
| private

Parse a floating number.

Parameters

  token | The token to parse
  result | Store the number here

Returns
  true if `token` is a valid number or false for an error

Definition at line 230 of file parse.cpp.

Referenced by get_primary().

231 {
232 std::istringstream stream{token};
233 // If the value overflows or is otherwise invalid, return false.
234 double value{};
235 if (not (stream >> value))
236 return false;
237 result = node{number{value}};
238 return true;
239 }
number
Definition: number.hpp:16
node
Definition: node.hpp:28

void parser::get_identifier | ( | std::string & | identifier | ) |
| private

Parse an identifer.

Parameters

  identifier | Store the identifier here.

Precondition
  first input character is alphabetic

Definition at line 102 of file parse.cpp.

References charify(), input_, isalnum(), and isalpha().

Referenced by get_token().

103 {
104 identifier.clear();
105 char c{};
106 if (not input_.get(c))
107 return;
108 if (not isalpha(c))
109 throw syntax_error{"expected alphabetic, got " + charify(c)};
110 identifier += c;
111 while (input_.get(c)) {
112 if (not isalnum(c)) {
113 input_.unget();
114 return;
115 }
116 identifier += c;
117 }
118 return;
119 }
parser::charify
std::string charify(char c)
Definition: parse.cpp:17
syntax_error
Definition: calc_error.hpp:24
parser::isalpha
bool isalpha(char c) const
Definition: parse.hpp:185
parser::input_
std::istream & input_
Share the input stream.
Definition: parse.hpp:202
parser::isalnum
bool isalnum(char c) const
Definition: parse.hpp:190
parser::identifier
Definition: parse.hpp:32

bool parser::get_integer | ( | std::string const & | token,
|  | node & | result
| ) |  |
| private

Parse an integer.

Parameters

  token | The token to parse
  result | Store the number here

Returns
  true if `token` is a valid number or false for an error

Definition at line 219 of file parse.cpp.

Referenced by get_primary().

220 {
221 std::istringstream stream{token};
222 // If the value overflows or is otherwise invalid, return false.
223 long long value{};
224 if (not (stream >> value))
225 return false;
226 result = node{number{value}};
227 return true;
228 }
number
Definition: number.hpp:16
node
Definition: node.hpp:28

bool parser::get_mul_expr | ( | node & | result | ) |
| private

Parse a multiplicative expression.

    MUL_EXPR ::= UNARY | MUL_EXPR + UNARY | MUL_EXPR - UNARY

Parameters

  result | Store the result here

Returns
  true to continue parsing or false to stop (end of file or error)

Definition at line 331 of file parse.cpp.

References get_token(), get_unary(), and push_back().

Referenced by get_add_expr().

332 {
333 if (not get_unary(result))
334 return false;
335 std::string token{};
336 while (kind k = get_token(token)) {
337 if (k != '*' and k != '/') {
338 push_back(token, k);
339 return true;
340 } else {
341 node right{};
342 if (not get_unary(right))
343 throw syntax_error{"unterminated expression. Expected a unary-expression after " + token};
344 result = node(result, k, right);
345 }
346 }
347 return true;
348 }
node
Definition: node.hpp:28
parser::push_back
void push_back(std::string const &token, kind k)
Definition: parse.cpp:121
syntax_error
Definition: calc_error.hpp:24
parser::get_unary
bool get_unary(node &result)
Definition: parse.cpp:350
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::kind
kind
Definition: parse.hpp:32
template<class OutputIterator >

OutputIterator parser::get_namelist | ( | OutputIterator | output | ) |
| private

Parse a list of parameter names. Names are identifiers, separated by commas. The list can be empty. This is a template so the container type is unimportant. Any output iterator will do.

Parameters

  [out] | output | Store the identifiers here

Returns
  a copy of `output` after storing all the identifiers

Definition at line 216 of file parse.hpp.

References get_token(), and identifier.

Referenced by get_definition().

217 {
218 std::string token{};
219 while (kind k = get_token(token)) {
220 if (k == ')')
221 return output;
222 else if (k != identifier)
223 throw syntax_error{"expected function parameter, got " + token};
224 else {
225 *output = token;
226 ++output;
227
228 k = get_token(token);
229 if (k == ')')
230 return output;
231 if (k != ',')
232 throw syntax_error{"expected comma in function paramter list, got " + token};
233 }
234 }
235 throw syntax_error{"unexpected end of line in function parameter list"};
236 }
syntax_error
Definition: calc_error.hpp:24
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::kind
kind
Definition: parse.hpp:32
parser::identifier
Definition: parse.hpp:32

bool parser::get_primary | ( | node & | result | ) |
| private

Parse a primary expression.

    PRIMARY ::= NUMBER | IDENTIFIER | '(' EXPR ')' | FUNCTION_CALL
    FUNCTION_CALL ::= IDENTIFIER '(' OPT_EXPR_LIST ')'
    OPT_EXPR_LIST ::= empty | EXPR_LIST
    EXPR_LIST ::= EXPR | EXPR_LIST ',' EXPR

Parameters

  result | Store the result here

Returns
  true to continue parsing or false to stop (end of file or error)

Definition at line 392 of file parse.cpp.

References eof, floating_point, get_expr(), get_expr_list(), get_float(), get_integer(), get_token(), identifier, integer, and push_back().

Referenced by get_unary().

393 {
394 std::string token{};
395 kind k = get_token(token);
396 if (k == eof)
397 return false;
398
399 if (k == '(') {
400 // Parenthesized expression
401 if (not get_expr(result))
402 throw syntax_error{"expected expression, got end of line"};
403 k = get_token(token);
404 if (k != ')')
405 throw syntax_error{"expected ')', got " + token};
406 else
407 return true;
408 }
409
410 if (k == integer) {
411 // Integer literal
412 if (not get_integer(token, result))
413 throw syntax_error{"Invalid integer literal: " + token};
414 return true;
415 }
416
417 if (k == floating_point) {
418 // Integer literal
419 if (not get_float(token, result))
420 throw syntax_error{"Invalid integer literal: " + token};
421 return true;
422 }
423
424 if (k == identifier) {
425 // Identifier: variable or function call
426 std::string next{};
427 k = get_token(next);
428 if (k == '(') {
429 // function call
430 node_list arguments{};
431 get_expr_list(arguments);
432 result = node{std::move(token), std::move(arguments)};
433 } else {
434 static const node_list no_arguments;
435 // Variable reference or function call with no arguments
436 push_back(next, k);
437 result = node{std::move(token), no_arguments};
438 }
439 return true;
440 }
441 throw syntax_error{"expected a primary, got " + token};
442 }
parser::get_expr
bool get_expr(node &result)
Definition: parse.cpp:307
node
Definition: node.hpp:28
parser::push_back
void push_back(std::string const &token, kind k)
Definition: parse.cpp:121
parser::get_integer
bool get_integer(std::string const &token, node &result)
Definition: parse.cpp:219
parser::integer
Definition: parse.hpp:32
syntax_error
Definition: calc_error.hpp:24
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::get_float
bool get_float(std::string const &token, node &result)
Definition: parse.cpp:230
parser::floating_point
Definition: parse.hpp:32
parser::eof
Definition: parse.hpp:32
parser::kind
kind
Definition: parse.hpp:32
node_list
std::vector< node > node_list
A sequence of nodes.
Definition: node.hpp:15
parser::get_expr_list
void get_expr_list(node_list &result)
Definition: parse.cpp:371
parser::identifier
Definition: parse.hpp:32

bool parser::get_statement | ( | std::ostream & | output | ) |

Read one statement and store the parse tree in `result`. If the statement is an assignment or function definition, store the variable or function. If the statement is an expression, print the result to `output`.

    STATEMENT ::= DEFINITION | QUIT | EXPR | SAVE | LOAD
    SAVE ::= "save" FILENAME
    LOAD ::= "load" FILENAME
    FILENAME ::= quoted-string

Parameters

  output | The output stream.

Returns
  true to continue or false to end the loop

Exceptions

  parse_error | for various syntax and other errors

Definition at line 262 of file parse.cpp.

References eof, node::evaluate(), get_definition(), get_expr(), get_token(), identifier, load_library(), push_back(), save_library(), and set_function().

263 {
264 std::string token{};
265 kind k(get_token(token));
266 if (k == eof)
267 return false;
268
269 if (k == identifier and token == "def") {
270 node definition{};
271 identifier_list parameters{};
272 get_definition(token, parameters, definition);
273 set_function(token, node{std::move(parameters), definition});
274 return true;
275 }
276
277 if (k == identifier and token == "quit")
278 std::exit(0);
279
280 if (k == identifier and token == "save") {
281 std::string filename{};
282 if (get_token(filename) != string)
283 throw syntax_error{"expected FILENAME after save, got " + token};
284 save_library(filename);
285 output << "Library saved to " << filename << '\n';
286 }
287
288 if (k == identifier and token == "load") {
289 std::string filename{};
290 if (get_token(filename) != string)
291 throw syntax_error{"expected FILENAME after load, got " + token};
292 load_library(filename);
293 output << "Library loaded from " << filename << '\n';
294 }
295 // Otherwise, the statement must be an expression.
296 push_back(token, k);
297 node n{};
298 if (not get_expr(n))
299 return false;
300 else {
301 // Evaluate the expression and print the result.
302 output << n.evaluate() << '\n';
303 return true;
304 }
305 }
load_library
void load_library(std::string const &filename)
Definition: variables.cpp:100
parser::get_expr
bool get_expr(node &result)
Definition: parse.cpp:307
save_library
void save_library(std::string const &filename)
Definition: variables.cpp:79
node
Definition: node.hpp:28
parser::get_definition
void get_definition(std::string &name, identifier_list &parameters, node &definition)
Definition: parse.cpp:241
parser::push_back
void push_back(std::string const &token, kind k)
Definition: parse.cpp:121
syntax_error
Definition: calc_error.hpp:24
identifier_list
std::vector< std::string > identifier_list
A sequence of identifiers (e.g., parameter names).
Definition: node.hpp:21
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
set_function
void set_function(std::string const &name, node value)
Definition: variables.cpp:74
node::evaluate
number evaluate() const
Definition: node.cpp:73
parser::eof
Definition: parse.hpp:32
parser::kind
kind
Definition: parse.hpp:32
parser::identifier
Definition: parse.hpp:32

void parser::get_string | ( | std::string & | result,
|  | char | delimiter
| ) |  |
| private

Parse a quoted string. The caller passes the quote character in the `delimiter` argument.

Parameters

  [out] | result | Store the token here.
  [in] | delimiter | The quote character (`'` or `"`)

Definition at line 86 of file parse.cpp.

References get_escape(), and input_.

Referenced by get_token().

87 {
88 char c{};
89 while (input_.get(c)) {
90 if (c == delimiter)
91 return;
92 else if (c == '\\')
93 get_escape(result);
94 else if (c == '\n')
95 throw syntax_error{"unterminated string"};
96 else
97 result += c;
98 }
99 throw syntax_error{"unterminated string"};
100 }
syntax_error
Definition: calc_error.hpp:24
parser::input_
std::istream & input_
Share the input stream.
Definition: parse.hpp:202
parser::get_escape
void get_escape(std::string &str)
Definition: parse.cpp:41

parser::kind parser::get_token | ( | std::string & | token | ) |
| private

Parse a token. A token can be a keyword, a literal or a symbol.

    TOKEN ::= IDENTIFIER | NUMBER | SYMBOL | STRING
    IDENTIIFER ::= ALPHA (ALPHA | DIGIT)*
    NUMBER ::= INTEGER | FLOATING-POINT
    INTEGER ::= DIGIT+
    FLOATING_POINT ::= DIGIT+ '.' DIGITS+ ('E' SIGN? DIGITS+)? | DIGIT+ ('.' DIGITS+)? 'E' SIGN? DIGITS+
    SYMBOL ::= '+' | '-' | '*' | '/' | '%' | '(' | ')' | '=' | ','

Parameters

  token | Store the text of the token here.

Returns
  the token kind

Definition at line 130 of file parse.cpp.

References charify(), eof, floating_point, get_identifier(), get_string(), identifier, input_, integer, isalpha(), kind_, string, and token_.

Referenced by get_add_expr(), get_definition(), get_expr_list(), get_mul_expr(), get_namelist(), get_primary(), get_statement(), and get_unary().

131 {
132 if (not token_.empty())
133 {
134 kind result(kind_);
135 token = token_;
136
137 token_.clear();
138 kind_ = eof;
139
140 return result;
141 }
142
143 char c{};
144 if (not (input_ >> c)) {
145 token = "end of line";
146 return eof;
147 }
148 if (isalpha(c)) {
149 input_.unget();
150 get_identifier(token);
151 return identifier;
152 }
153
154 if (c == '\'' or c == '"') {
155 // Quoted string
156 token.clear();
157 get_string(token, c);
158 return string;
159 }
160
161 // Get a numeric literal.
162 token.clear();
163 if (c == '+' or c == '-' or c == '*' or c == '/' or c == '%' or c == '(' or c == ')' or c == '=' or c == ',') {
164 token += c;
165 return static_cast<kind>(c);
166 }
167
168 if (c < '0' or c > '9') {
169 input_.unget();
170 throw syntax_error{"expected digit, got " + charify(c)};
171 }
172
173 kind k = integer;
174
175 while (c >= '0' and c <= '9') {
176 token += c;
177 if (not input_.get(c))
178 return k;
179 }
180 if (c == '.') {
181 k = floating_point;
182 token += c;
183 if (not input_.get(c))
184 throw syntax_error{"unterminated number: expected digit after the decimal point"};
185 if (c < '0' or c > '9') {
186 input_.unget();
187 throw syntax_error{"expected digit after decimal point, got " + charify(c)};
188 }
189 while (c >= '0' and c <= '9') {
190 token += c;
191 if (not input_.get(c))
192 return k;
193 }
194 }
195 if (c == 'e' or c == 'E') {
196 k = floating_point;
197 token += c;
198 if (not input_.get(c))
199 throw syntax_error{"unterminated number: expected digit in the exponent"};
200 if (c == '-' or c == '+') {
201 token += c;
202 if (not input_.get(c))
203 throw syntax_error{"unterminated number: expected digit after sign in the exponent"};
204 }
205 if (c < '0' or c > '9') {
206 input_.unget();
207 throw syntax_error{"expected digit in the exponent, got " + charify(c)};
208 }
209 while (c >= '0' and c <= '9') {
210 token += c;
211 if (not input_.get(c))
212 return k;
213 }
214 }
215 input_.unget();
216 return k;
217 }
parser::get_string
void get_string(std::string &result, char delimiter)
Definition: parse.cpp:86
parser::get_identifier
void get_identifier(std::string &identifier)
Definition: parse.cpp:102
parser::charify
std::string charify(char c)
Definition: parse.cpp:17
parser::integer
Definition: parse.hpp:32
syntax_error
Definition: calc_error.hpp:24
parser::isalpha
bool isalpha(char c) const
Definition: parse.hpp:185
parser::token_
std::string token_
One token push-back.
Definition: parse.hpp:204
parser::floating_point
Definition: parse.hpp:32
parser::input_
std::istream & input_
Share the input stream.
Definition: parse.hpp:202
parser::kind_
kind kind_
The kind of token that was pushed back.
Definition: parse.hpp:205
parser::eof
Definition: parse.hpp:32
parser::kind
kind
Definition: parse.hpp:32
parser::string
Definition: parse.hpp:32
parser::identifier
Definition: parse.hpp:32

bool parser::get_unary | ( | node & | result | ) |
| private

Parse a unary expression.

    UNARY ::= '-' PRIMARY | '+' PRIMARY | PRIMARY

Parameters

  result | Store the result here

Returns
  true to continue parsing or false to stop (end of file or error)

Definition at line 350 of file parse.cpp.

References eof, get_primary(), get_token(), and push_back().

Referenced by get_mul_expr().

351 {
352 std::string token{};
353 kind k = get_token(token);
354 if (k == eof)
355 return false;
356 if (k == '-') {
357 if (not get_primary(result))
358 throw syntax_error{"expected primary after unary " + token + ", got end of line"};
359 result = node(k, result);
360 return true;
361 } else if (k == '+') {
362 if (not get_primary(result))
363 throw syntax_error{"expected primary after unary +, got end of line"};
364 return true;
365 } else {
366 push_back(token, k);
367 return get_primary(result);
368 }
369 }
node
Definition: node.hpp:28
parser::push_back
void push_back(std::string const &token, kind k)
Definition: parse.cpp:121
parser::get_primary
bool get_primary(node &result)
Definition: parse.cpp:392
syntax_error
Definition: calc_error.hpp:24
parser::get_token
kind get_token(std::string &token)
Definition: parse.cpp:130
parser::eof
Definition: parse.hpp:32
parser::kind
kind
Definition: parse.hpp:32

bool parser::isalnum | ( | char | c | ) | const
| inline private

Return true if `c` is alphanumeric. Use the locale of the input stream.

Parameters

  c | The character to test.

Definition at line 190 of file parse.hpp.

References ctype_.

Referenced by get_identifier().

190 { return ctype_.is(ctype_.alnum, c); }
parser::ctype_
std::ctype< char > const & ctype_
Cache the ctype facet for checking character categories.
Definition: parse.hpp:203

bool parser::isalpha | ( | char | c | ) | const
| inline private

Return true if `c` is alphabetic. Use the locale of the input stream.

Parameters

  c | The character to test.

Definition at line 185 of file parse.hpp.

References ctype_.

Referenced by get_identifier(), and get_token().

185 { return ctype_.is(ctype_.alpha, c); }
parser::ctype_
std::ctype< char > const & ctype_
Cache the ctype facet for checking character categories.
Definition: parse.hpp:203

bool parser::isdigit | ( | char | c | ) | const
| inline private

Return true if `c` is a digit. Use the locale of the input stream.

Parameters

  c | The character to test.

Definition at line 195 of file parse.hpp.

References ctype_.

195 { return ctype_.is(ctype_.digit, c); }
parser::ctype_
std::ctype< char > const & ctype_
Cache the ctype facet for checking character categories.
Definition: parse.hpp:203

bool parser::isprint | ( | char | c | ) | const
| inline private

Return true if `c` is printable. Use the locale of the input stream.

Parameters

  c | The character to test.

Definition at line 200 of file parse.hpp.

References ctype_.

Referenced by charify().

200 { return ctype_.is(ctype_.print, c); }
parser::ctype_
std::ctype< char > const & ctype_
Cache the ctype facet for checking character categories.
Definition: parse.hpp:203

void parser::push_back | ( | std::string const & | token,
|  | kind | k
| ) |  |
| private

Push back a token. The next call to get_token() will return the pushed-back token.

Parameters

  token | The token to push back.
  k | The kind of token being pushed back

Definition at line 121 of file parse.cpp.

References eof, kind_, and token_.

Referenced by get_add_expr(), get_expr_list(), get_mul_expr(), get_primary(), get_statement(), and get_unary().

122 {
123 kind_ = k;
124 if (kind_ == eof)
125 token_ = "end of line";
126 else
127 token_ = token;
128 }
parser::token_
std::string token_
One token push-back.
Definition: parse.hpp:204
parser::kind_
kind kind_
The kind of token that was pushed back.
Definition: parse.hpp:205
parser::eof
Definition: parse.hpp:32

## Member Data Documentation

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

Cache the ctype facet for checking character categories.

Definition at line 203 of file parse.hpp.

Referenced by get_escape(), isalnum(), isalpha(), isdigit(), and isprint().

std::istream& parser::input_
| private

Share the input stream.

Definition at line 202 of file parse.hpp.

Referenced by get_escape(), get_identifier(), get_string(), and get_token().

kind parser::kind_
| private

The kind of token that was pushed back.

Definition at line 205 of file parse.hpp.

Referenced by get_token(), and push_back().

std::string parser::token_
| private

One token push-back.

Definition at line 204 of file parse.hpp.

Referenced by get_token(), and push_back().

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

- parse.hpp
- parse.cpp