55 template<
class CharSeq>
69 template<
class CharSeq>
83 template<
class CharSeq>
96 template<
class CharSeq>
109 template<
class CharSeq>
114 if (!_ternary_cond_stack.size()) {
116 "':' of ternary conditional without preceding '?' "
122 evaluation ternary_cond = _ternary_cond_stack.back();
123 _ternary_cond_stack.pop_back();
134 template<
class CharSeq>
148 template<
class CharSeq>
149 template<
unsigned Precedence>
150 pair<typename expression_parser<CharSeq>::infix_operation,
bool>
157 infix_operation rightmost_op =
nullptr;
158 bool short_circuitable =
false;
159 size_t mark = size_t(chew);
160 int paren_balance = 0;
161 bool have_infix =
false;
162 bool have_lhs =
false;
163 for ( ;*chew && size_t(chew) < end;
164 have_lhs = !have_infix,chew(
greyspace)) {
165 if (have_lhs && paren_balance == 0) {
166 size_t op_off = size_t(chew);
170 if (Precedence == ternary_if) {
172 op_end = size_t(++chew);
178 short_circuitable =
true;
179 if (Precedence == ternary_either_or) {
181 op_end = size_t(++chew);
187 short_circuitable =
true;
188 if (Precedence == comma) {
190 op_end = size_t(++chew);
197 Precedence == boolean_and) {
198 short_circuitable =
true;
200 op_end = size_t(++chew);
202 }
else if (Precedence == bit_and) {
204 op_end = size_t(chew);
211 Precedence == boolean_or) {
212 short_circuitable =
true;
214 op_end = size_t(++chew);
216 }
else if (Precedence == bit_or) {
218 op_end = size_t(chew);
224 if (Precedence == bit_xor) {
226 op_end = size_t(++chew);
233 if (Precedence == eq) {
235 op_end = size_t(++chew);
248 op_end = size_t(++chew);
253 if (Precedence == lshift) {
255 op_end = size_t(++chew);
262 if (Precedence == lt) {
264 op_end = size_t(chew);
274 op_end = size_t(++chew);
279 if (Precedence == rshift) {
281 op_end = size_t(++chew);
288 if (Precedence == gt) {
290 op_end = size_t(chew);
297 if (Precedence == neq) {
299 op_end = size_t(++chew);
308 if (Precedence == add) {
310 op_end = size_t(++chew);
316 if (Precedence == subtract) {
318 op_end = size_t(++chew);
324 if (Precedence == mult) {
326 op_end = size_t(++chew);
332 if (Precedence == divide) {
334 op_end = size_t(++chew);
340 if (Precedence == mod) {
342 op_end = size_t(++chew);
351 if (Precedence == boolean_and) {
353 op_end = size_t(++chew);
364 size_t mark = size_t(chew);
370 if (Precedence == bit_and) {
372 op_end = size_t(++chew);
382 if (Precedence == bit_or) {
384 op_end = size_t(++chew);
396 if (Precedence == boolean_or) {
398 op_end = size_t(++chew);
413 if (Precedence == neq) {
415 op_end = size_t(++chew);
427 if (Precedence == bit_xor) {
429 op_end = size_t(++chew);
440 if (*chew ==
')' && --paren_balance < 0) {
443 paren_balance += *chew ==
'(';
447 return make_pair(rightmost_op,short_circuitable);
450 template<
class CharSeq>
454 gripe <<
", in expansion of \"" << _ref->invocation() <<
'\"';
459 template<
class CharSeq>
460 template<
unsigned Precedence>
464 pair<infix_operation,bool> op(
nullptr,
false);
466 size_t start_lhs = size_t(chew);
467 size_t end_lhs = start_lhs;
468 size_t start_rhs = end_lhs;
470 for (; (op = seek_rightmost_infix<Precedence>(
471 chew,end,start_rhs,end_lhs)),op.first !=
nullptr; ) {
472 lhs = next_evaluator<Precedence>(chew,start_rhs);
473 if (
size_t(chew(
greyspace)) != start_rhs) {
478 evaluation rhs = next_evaluator<Precedence - 1>(chew,end);
479 size_t end_rhs = size_t(chew);
485 cut(start_lhs,end_lhs);
494 cut(start_rhs,end_rhs);
508 return next_evaluator<Precedence - 1>(chew,end);
511 template<
class CharSeq>
524 result = unary_op(chew,end);
534 result = unary_op(chew,end);
543 size_t start = size_t(chew);
545 result = infix_op<max>(chew,end);
557 delete_paren(start,
size_t(chew));
565 result = unary_op(chew,end);
573 result = unary_op(chew,end);
581 if (isdigit(*chew)) {
582 size_t mark = size_t(chew);
594 size_t mark = size_t(chew);
599 paren = *chew ==
'(';
618 if (!sloc->configured()) {
628 result = unary_op(chew,end);
637 result = unary_op(chew,end);
650 size_t mark = size_t(chew);
663 size_t mark = size_t(chew);
664 if (*chew ==
'L' || *chew ==
'u' || *chew ==
'U') {
684 if (!sloc->
invoked() && args) {
688 if (!ref.eval().insoluble() && !ref.args() &&
702 gripe <<
'\"' << ref.invocation()
703 <<
"\" expands to nothing within expression";
704 defer_diagnostic(gripe);
706 if (ref.complete()) {
708 gripe <<
'\"' << ref.invocation()
709 <<
"\" expands to non-expression >>"
710 << ref.expansion() <<
"<< within expression";
711 defer_diagnostic(gripe);
714 gripe <<
"Macro expansion of \""
717 "Will exceed max expansion size "
720 defer_diagnostic(gripe);
733 gripe <<
"Ill-formed \"" << bad;
735 gripe <<
"\" after \"" << good <<
'\"';
737 defer_diagnostic(gripe);
743 template<
class CharSeq>
747 _eval = infix_op<max>(chew,size_t(-1));
748 bool orphan_if =
false;
749 if (_ternary_cond_stack.size()) {
753 if ((chew || orphan_if)) {
754 _eval.set_insoluble();
755 std::shared_ptr<diagnostic_base> gripe;
759 <<
"'?' of ternary conditional without following ':' "
767 *gripe <<
"Ill-formed \"" << bad <<
"\" after \""
789 template<
class CharSeq>
792 string const & in = _seq.str();
793 if (is_simplified()) {
796 for ( ; i < _start; ++i) {
799 if (i > 0 && _deletions[i] && isgraph(in[i - 1])) {
803 for ( ; ptrdiff_t(i) <= _last_deletion; ++i) {
804 if (!_deletions[i]) {
808 if (i + 1 < _seq.size()) {
809 out += _seq.substr(i);
819 template<
class CharSeq>
824 : _ternary_cond_stack(0),_seq(seq),_start(start),
825 _cuts(0),_last_deletion(-1),_ref(ref)
evaluation op_bit_and(evaluation const &lhs, evaluation const &rhs)
Bitwise AND operator.
error_msg< 20 > error_ternary_cond_incomplete
Report an incomplete ternary conditional operator.
template struct traits::is_random_access_char_sequence<T> exports a static const boolean member value...
static bool plaintext()
Are we to omit parsing for C/C++ comments?
static bool implicit()
Do we implicitly --undef all unconfigured symbols?
evaluation op_rshift(evaluation const &lhs, evaluation const &rhs)
Right-shift operator.
template struct warning_msg<Id> generically encapsulates a warning diagnostic.
unsigned long long raw() const
Get the bits comprising the integer as an unsigned long long
static integer read_numeral(chewer< CharSeq > &chew)
Read a numeral from a chewer<CharSeq>
bool is_start_char(char ch)
Say whether a character can be the first of an identifier.
template struct error_msg<Id> generically encapsulates an error diagnostic.
evaluation apply(infix_operation op, evaluation &lhs, evaluation &rhs)
Apply a infix operation to arguments.
std::shared_ptr< std::string const > defn() const
Get a pointer to the symbol's definition; null if undefined.
integer const & value() const
Get the integral value of the expression.
evaluation op_add(evaluation const &lhs, evaluation const &rhs)
Addition operator.
evaluation op_lt(evaluation const &lhs, evaluation const &rhs)
Less-than operator.
std::string simplified() const
Get the most simplified form of the expression.
bool invoked() const
Say whether the symbol has been invoked.
evaluation op_ne(evaluation const &lhs, evaluation const &rhs)
Inequality operator.
struct symbol::locator encapsulates a symbol table entry.
bool good() const
Say whether the integer is of valid type, not INT_UNDEF
void set_parens_off(size_t loff, size_t roff)
Set the text offsets of surrounding parentheses.
#define TOK_ALT_BIT_NOT
Constant denoting the alternative bitwise negation operator.
evaluation op_lshift(evaluation const &lhs, evaluation const &rhs)
Left-shift operator.
evaluation op_subtract(evaluation const &lhs, evaluation const &rhs)
Subtraction operator.
void defer_diagnostic(diagnostic_base &gripe)
Defer a diagnostic, with the current line context appended if a source line is being parsed...
size_t lparen_off() const
Get the text offset of the left parenthesis, if any. -1 if none.
A base class for diagnostic classes.
#define TOK_DEFINED
Constant denoting the defined operator.
bool configured() const
Say whether the symbol is configured.
evaluation op_le(evaluation const &lhs, evaluation const &rhs)
Less-than-or-equal operator.
evaluation op_mod(evaluation const &lhs, evaluation const &rhs)
Modulus operator.
void set_insoluble()
Classify the expression as insoluble.
Undetermined type or invalid.
Class argument_list encapsulates a list of macro arguments, i.e. the arguments to a macro reference...
evaluation op_ge(evaluation const &lhs, evaluation const &rhs)
Greater-than-or-equal operator.
Class integer encapsulates an integer of some type.
warning_msg< 14 > warning_zero_divide
Report a divide by zero was found in an expression.
std::string citable(chewer< std::string > &chew, size_t len=std::string::npos)
Make a citable version of length-delimited text.
static locator lookup(std::string const &id)
Lookup an identifier in the symbol table.
void set_value(integer const &val)
Set the integral value of the expression.
bool variadic() const
Say whether this symbol is a variadic macro.
expression_parser(chewer< sequence_type > &chew, reference const *ref=nullptr)
Construct given a chewer<sequence_type>
evaluation op_eq(evaluation const &lhs, evaluation const &rhs)
Equality operator.
evaluation op_comma(evaluation const &lhs, evaluation const &rhs)
Comma operator.
evaluation infix_op(chewer< sequence_type > &chew, size_t end)
Evaluator for infix operations.
evaluation op_or(evaluation const &lhs, evaluation const &rhs)
Inclusive-or operator.
size_t rparen_off() const
Get the text offset of the right parenthesis, if any. -1 if none.
std::string read(chewer< CharSeq > &chew)
Read an identifier from an chewer<CharSeq>
bool defined() const
Is the symbol defined.
static size_t flush(unsigned reason)
Emit all queued diagnostics that match a reason-code.
chew_mode::continuation const continuation
An exemplar chew_mode::continuation
evaluation op_mult(evaluation const &lhs, evaluation const &rhs)
Multiplication operator.
error_msg< 14 > error_unbalanced_paren
Report unbalanced parenthesis.
The tag class is inserted in a diagnostic_base to tell it to emit itself.
evaluation op_divide(evaluation const &lhs, evaluation const &rhs)
Division operator.
evaluation op_ternary_either_or(evaluation const &lhs, evaluation const &rhs)
The ':' "operator". Pops the evaluation of the preceding `cond ?' from the stack. If cond is true, returns lhs; if cond is false returns rhs, else returns evaluation()
chew_mode::greyspace const greyspace
An exemplar chew_mode::greyspace
bool resolved() const
Say whether the expression has been resolved.
The tag class is inserted in a diagnostic_base to tell it to defer itself.
evaluation op_and(evaluation const &lhs, evaluation const &rhs)
And operator.
bool is_valid_char(char ch)
Say whether a character can occur in an identifier.
integer_type type() const
Get the type of the integer
evaluation op_bit_or(evaluation const &lhs, evaluation const &rhs)
Bitwise OR operator.
static constexpr unsigned max_expansion_size()
Cut-off size for macro-expansions.
void set_parameters(formal_parameter_list const ¶ms)
Set a macro parameter list for the symbol.
`template struct chewer<CharSeq> is a cursor-like type that is associated with a character-sequence t...
template class canonical<What> encapsulates the canonical representation of values of type What...
bool insoluble() const
Say whether the expression is insoluble.
evaluation op_gt(evaluation const &lhs, evaluation const &rhs)
Greater-than operator.
void parse(chewer< sequence_type > &chew)
Evaluate text from a chewer<sequence_type>
static integer read_char(chewer< CharSeq > &chew)
Read a character constant from a text offset, returning its value as an integer.
evaluation op_bit_xor(evaluation const &lhs, evaluation const &rhs)
Bitwise XOR operator.
bool is_false() const
Say whether the expression is false.
evaluation unary_op(chewer< sequence_type > &chew, size_t end)
Evaluator for innermost subexpressions.
#define TOK_ALT_BOOLEAN_NOT
Constant denoting the alternative boolean negation operator.
static std::string pretty()
Get a pretty printable version of the current input line.
bool is_true() const
Say whether the expression is true.
evaluation op_ternary_if(evaluation const &lhs, evaluation const &rhs)
The '?' "operator". Stacks its left operand; returns its right.
bool self_referential() const
Say whether the symbol's definition is infinitely regressive.
struct evaluation represents the result of evaluating a putative expression.
std::pair< expression_parser::infix_operation, bool > seek_rightmost_infix(chewer< sequence_type > &chew, size_t end, size_t &op_start, size_t &op_end)
Search for the rightmost binary operator at a given level of precedence within delimited text...
unsigned short & net_infix_ops()
Get/set the residual number of binary operators in the expression, after simplification.