coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
expression_parser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2007-2013 Mike Kinghan, imk@burroingroingjoing.com *
3  * All rights reserved. *
4  * *
5  * Contributed originally by Mike Kinghan, imk@burroingroingjoing.com *
6  * *
7  * Redistribution and use in source and binary forms, with or without *
8  * modification, are permitted provided that the following conditions *
9  * are met: *
10  * *
11  * Redistributions of source code must retain the above copyright *
12  * notice, this list of conditions and the following disclaimer. *
13  * *
14  * Redistributions in binary form must reproduce the above copyright *
15  * notice, this list of conditions and the following disclaimer in the *
16  * documentation and/or other materials provided with the distribution. *
17  * *
18  * Neither the name of Mike Kinghan nor the names of its contributors *
19  * may be used to endorse or promote products derived from this software *
20  * without specific prior written permission. *
21  * *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
29  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
32  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
33  * DAMAGE. *
34  * *
35  **************************************************************************/
36 #include "expression_parser.h"
37 #include "diagnostic.h"
38 #include "citable.h"
39 #include "lexicon.h"
40 #include "integer_constant.h"
41 #include "canonical.h"
42 #include "reference.h"
43 #include "options.h"
44 #include "line_despatch.h"
45 #include "expansion_base.h"
46 
51 
53 using namespace std;
54 
55 template<class CharSeq>
58  evaluation const & lhs,
59  evaluation const & rhs)
60 {
61  if (lhs.is_true() || rhs.is_true()) {
62  return evaluation(1);
63  } else if (lhs.is_false() && rhs.is_false()) {
64  return evaluation(0);
65  }
66  return evaluation();
67 }
68 
69 template<class CharSeq>
72  evaluation const & lhs,
73  evaluation const & rhs)
74 {
75  if (rhs.is_true() && lhs.is_true()) {
76  return evaluation(1);
77  } else if (rhs.is_false() || lhs.is_false()) {
78  return evaluation(0);
79  }
80  return evaluation();
81 }
82 
83 template<class CharSeq>
86  evaluation const & lhs,
87  evaluation const & rhs)
88 {
89  if (rhs.value().good() && rhs.value().raw() == 0) {
90  warning_zero_divide() << "Divide by zero" << emit();
91  return evaluation();
92  }
93  return evaluation(lhs.value() / rhs.value());
94 }
95 
96 template<class CharSeq>
99  evaluation const & lhs,
100  evaluation const & rhs)
101 {
102  if (rhs.value().good() && rhs.value().raw() == 0) {
103  warning_zero_divide() << "Divide by zero" << emit();
104  return evaluation();
105  }
106  return evaluation(lhs.value() % rhs.value());
107 }
108 
109 template<class CharSeq>
111  evaluation const & lhs,
112  evaluation const & rhs)
113 {
114  if (!_ternary_cond_stack.size()) {
116  "':' of ternary conditional without preceding '?' "
117  "in \"" << citable(!options::plaintext(),_seq)
118  << "\"" << defer();
119  return evaluation();
120  }
121  else {
122  evaluation ternary_cond = _ternary_cond_stack.back();
123  _ternary_cond_stack.pop_back();
124  if (ternary_cond.is_true()) {
125  return lhs;
126  }
127  if (ternary_cond.is_false()) {
128  return rhs;
129  }
130  return evaluation();
131  }
132 }
133 
134 template<class CharSeq>
136  infix_operation op,
137  evaluation & lhs, evaluation &rhs)
138 {
139  evaluation result = (this->*op)(lhs,rhs);
140  if (!result.resolved()) {
141  result.net_infix_ops() = 1 + lhs.net_infix_ops() + lhs.net_infix_ops();
142  } else {
143  result.net_infix_ops() = 0;
144  }
145  return result;
146 }
147 
148 template<class CharSeq>
149 template<unsigned Precedence>
150 pair<typename expression_parser<CharSeq>::infix_operation,bool>
152  chewer<CharSeq> & chew,
153  size_t end,
154  size_t & op_start,
155  size_t & op_end)
156 {
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);
167  switch(*chew) {
168  case '?':
169  have_infix = true;
170  if (Precedence == ternary_if) {
171  op_start = op_off;
172  op_end = size_t(++chew);
173  rightmost_op = &expression_parser::op_ternary_if;
174  }
175  continue;
176  case ':':
177  have_infix = true;
178  short_circuitable = true;
179  if (Precedence == ternary_either_or) {
180  op_start = op_off;
181  op_end = size_t(++chew);
183  }
184  continue;
185  case ',':
186  have_infix = true;
187  short_circuitable = true;
188  if (Precedence == comma) {
189  op_start = op_off;
190  op_end = size_t(++chew);
191  rightmost_op = &expression_parser::op_comma;
192  }
193  continue;
194  case '&':
195  have_infix = true;
196  if (chew(+1,continuation) && *chew == '&' &&
197  Precedence == boolean_and) {
198  short_circuitable = true;
199  op_start = op_off;
200  op_end = size_t(++chew);
201  rightmost_op = &expression_parser::op_and;
202  } else if (Precedence == bit_and) {
203  op_start = op_off;
204  op_end = size_t(chew);
205  rightmost_op = &expression_parser::op_bit_and;
206  }
207  continue;
208  case '|':
209  have_infix = true;
210  if (chew(+1,continuation) && *chew == '|' &&
211  Precedence == boolean_or) {
212  short_circuitable = true;
213  op_start = op_off;
214  op_end = size_t(++chew);
215  rightmost_op = &expression_parser::op_or;
216  } else if (Precedence == bit_or) {
217  op_start = op_off;
218  op_end = size_t(chew);
219  rightmost_op = &expression_parser::op_bit_or;
220  }
221  continue;
222  case '^':
223  have_infix = true;
224  if (Precedence == bit_xor) {
225  op_start = op_off;
226  op_end = size_t(++chew);
227  rightmost_op = &expression_parser::op_bit_xor;
228  }
229  continue;
230  case '=':
231  if (chew(+1,continuation) && *chew == '=') {
232  have_infix = true;
233  if (Precedence == eq) {
234  op_start = op_off;
235  op_end = size_t(++chew);
236  rightmost_op = &expression_parser::op_eq;
237  continue;
238  }
239  }
240  have_infix = false;
241  continue;
242  case '<':
243  have_infix = true;
244  if (chew(+1,continuation)) {
245  if (*chew == '=' &&
246  Precedence == le) {
247  op_start = op_off;
248  op_end = size_t(++chew);
249  rightmost_op = &expression_parser::op_le;
250  continue;
251  }
252  if (*chew == '<') {
253  if (Precedence == lshift) {
254  op_start = op_off;
255  op_end = size_t(++chew);
256  rightmost_op = &expression_parser::op_lshift;
257  }
258  ++chew;
259  continue;
260  }
261  }
262  if (Precedence == lt) {
263  op_start = op_off;
264  op_end = size_t(chew);
265  rightmost_op = &expression_parser::op_lt;
266  }
267  continue;
268  case '>':
269  have_infix = true;
270  if (chew(+1,continuation)) {
271  if (*chew == '=' &&
272  Precedence == ge) {
273  op_start = op_off;
274  op_end = size_t(++chew);
275  rightmost_op = &expression_parser::op_ge;
276  continue;
277  }
278  if (*chew == '>') {
279  if (Precedence == rshift) {
280  op_start = op_off;
281  op_end = size_t(++chew);
282  rightmost_op = &expression_parser::op_rshift;
283  }
284  ++chew;
285  continue;
286  }
287  }
288  if (Precedence == gt) {
289  op_start = op_off;
290  op_end = size_t(chew);
291  rightmost_op = &expression_parser::op_gt;
292  }
293  continue;
294  case '!':
295  if (chew(+1,continuation) && *chew == '=') {
296  have_infix = true;
297  if (Precedence == neq) {
298  op_start = op_off;
299  op_end = size_t(++chew);
300  rightmost_op = &expression_parser::op_ne;
301  }
302  continue;
303  }
304  have_infix = false;
305  continue;
306  case '+':
307  have_infix = true;
308  if (Precedence == add) {
309  op_start = op_off;
310  op_end = size_t(++chew);
311  rightmost_op = &expression_parser::op_add;
312  }
313  continue;
314  case '-':
315  have_infix = true;
316  if (Precedence == subtract) {
317  op_start = op_off;
318  op_end = size_t(++chew);
319  rightmost_op = &expression_parser::op_subtract;
320  }
321  continue;
322  case '*':
323  have_infix = true;
324  if (Precedence == mult) {
325  op_start = op_off;
326  op_end = size_t(++chew);
327  rightmost_op = &expression_parser::op_mult;
328  }
329  continue;
330  case '/':
331  have_infix = true;
332  if (Precedence == divide) {
333  op_start = op_off;
334  op_end = size_t(++chew);
335  rightmost_op = &expression_parser::op_divide;
336  }
337  continue;
338  case '%':
339  have_infix = true;
340  if (Precedence == mod) {
341  op_start = op_off;
342  op_end = size_t(++chew);
343  rightmost_op = &expression_parser::op_mod;
344  }
345  continue;
346  case 'a':
347  if (chew(+1,continuation) && *chew == 'n' &&
348  chew(+1,continuation) && *chew == 'd' &&
349  !(++chew && identifier::is_valid_char(*chew))) {
350  have_infix = true;
351  if (Precedence == boolean_and) {
352  op_start = op_off;
353  op_end = size_t(++chew);
354  rightmost_op = &expression_parser::op_and;
355  }
356  continue;
357  }
358  have_infix = false;
359  continue;
360  case 'b':
361  if (chew(+1,continuation) && *chew == 'i' &&
362  chew(+1,continuation) && *chew == 't' &&
363  chew(+1,continuation) && *chew == '_') {
364  size_t mark = size_t(chew);
365  if (chew(+1,continuation) && *chew == 'a' &&
366  chew(+1,continuation) && *chew == 'n' &&
367  chew(+1,continuation) && *chew == 'd' &&
368  !(++chew && identifier::is_valid_char(*chew))) {
369  have_infix = true;
370  if (Precedence == bit_and) {
371  op_start = op_off;
372  op_end = size_t(++chew);
373  rightmost_op = &expression_parser::op_bit_and;
374  }
375  continue;
376  }
377  chew = mark;
378  if (chew(+1,continuation) && *chew == 'o' &&
379  chew(+1,continuation) && *chew == 'r' &&
380  !(++chew && identifier::is_valid_char(*chew))) {
381  have_infix = true;
382  if (Precedence == bit_or) {
383  op_start = op_off;
384  op_end = size_t(++chew);
385  rightmost_op = &expression_parser::op_bit_or;
386  }
387  continue;
388  }
389  }
390  have_infix = false;
391  continue;
392  case 'o':
393  if (chew(+1,continuation) && *chew == 'r' &&
394  !(++chew && identifier::is_valid_char(*chew))) {
395  have_infix = true;
396  if (Precedence == boolean_or) {
397  op_start = op_off;
398  op_end = size_t(++chew);
399  rightmost_op = &expression_parser::op_or;
400  }
401  continue;
402  }
403  have_infix = false;
404  continue;
405  case 'n':
406  if (chew(+1,continuation) && *chew == 'o' &&
407  chew(+1,continuation) && *chew == 't' &&
408  chew(+1,continuation) && *chew == '_' &&
409  chew(+1,continuation) && *chew == 'e' &&
410  chew(+1,continuation) && *chew == 'q' &&
411  !(++chew && identifier::is_valid_char(*chew))) {
412  have_infix = true;
413  if (Precedence == neq) {
414  op_start = op_off;
415  op_end = size_t(++chew);
416  rightmost_op = &expression_parser::op_ne;
417  }
418  continue;
419  }
420  have_infix = false;
421  continue;
422  case 'x':
423  if (chew(+1,continuation) && *chew == 'o' &&
424  chew(+1,continuation) && *chew == 'r' &&
425  !(++chew && identifier::is_valid_char(*chew))) {
426  have_infix = true;
427  if (Precedence == bit_xor) {
428  op_start = op_off;
429  op_end = size_t(++chew);
430  rightmost_op = &expression_parser::op_bit_xor;
431  }
432  continue;
433  }
434  have_infix = false;
435  continue;
436  default:;
437  }
438  }
439  have_infix = false;
440  if (*chew == ')' && --paren_balance < 0) {
441  break;
442  }
443  paren_balance += *chew == '(';
444  ++chew;
445  }
446  chew = mark;
447  return make_pair(rightmost_op,short_circuitable);
448 }
449 
450 template<class CharSeq>
452 {
453  if (_ref) {
454  gripe << ", in expansion of \"" << _ref->invocation() << '\"';
455  }
456  gripe << ", in \"" << line_despatch::pretty() << '\"'<< defer();
457 }
458 
459 template<class CharSeq>
460 template<unsigned Precedence>
463 {
464  pair<infix_operation,bool> op(nullptr,false);
465  evaluation lhs;
466  size_t start_lhs = size_t(chew);
467  size_t end_lhs = start_lhs;
468  size_t start_rhs = end_lhs;
469  chew(greyspace);
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) {
474  return lhs;
475  }
476  chew = end_lhs;
477  /* Evaluate rhs...*/
478  evaluation rhs = next_evaluator<Precedence - 1>(chew,end);
479  size_t end_rhs = size_t(chew);
480  evaluation result = apply(op.first,lhs,rhs);
481  if (lhs.resolved() && !rhs.resolved()) {
482  if (op.second || op.first == &expression_parser::op_ternary_if) {
483  result.net_infix_ops() = rhs.net_infix_ops();
484  result.set_parens_off(rhs.lparen_off(),rhs.rparen_off());
485  cut(start_lhs,end_lhs);
486  } else if (rhs.net_infix_ops() > 0) {
487  restore_paren(rhs.lparen_off(),rhs.rparen_off());
488  }
489  }
490  else if (rhs.resolved() && !lhs.resolved()) {
491  if (op.second) {
492  result.net_infix_ops() = lhs.net_infix_ops();
493  result.set_parens_off(lhs.lparen_off(),lhs.rparen_off());
494  cut(start_rhs,end_rhs);
495  } else if (lhs.net_infix_ops() > 0) {
496  restore_paren(lhs.lparen_off(),lhs.rparen_off());
497  }
498  } else if (!rhs.resolved() && !lhs.resolved()) {
499  if (rhs.net_infix_ops() > 0) {
500  restore_paren(rhs.lparen_off(),rhs.rparen_off());
501  }
502  if (lhs.net_infix_ops() > 0) {
503  restore_paren(lhs.lparen_off(),lhs.rparen_off());
504  }
505  }
506  return result;
507  }
508  return next_evaluator<Precedence - 1>(chew,end);
509 }
510 
511 template<class CharSeq>
514 {
516  evaluation result;
517  chew(greyspace);
518  do {
519  if (!chew) {
520  break;
521  }
522  if (*chew == '!') {
523  chew(+1,greyspace);
524  result = unary_op(chew,end);
525  if (result.net_infix_ops() > 0) {
526  restore_paren(result.lparen_off(),result.rparen_off());
527  break;
528  }
529  result.set_value(!result.value());
530  break;
531  }
532  if (*chew == '~') {
533  chew(+1,greyspace);
534  result = unary_op(chew,end);
535  if (result.net_infix_ops() > 0) {
536  restore_paren(result.lparen_off(),result.rparen_off());
537  break;
538  }
539  result.set_value(~result.value());
540  break;
541  }
542  if (*chew == '(') {
543  size_t start = size_t(chew);
544  chew(+1,greyspace);
545  result = infix_op<max>(chew,end);
546  chew(greyspace);
547  if (*chew != ')') {
548  /* Missing ')'*/
549  error_unbalanced_paren() << "Expected \")\" after \""
550  << citable(!options::plaintext(),_seq.substr(0,size_t(chew)))
551  << "\" in \""
552  << citable(!options::plaintext(),_seq) << '\"' << defer();
553  result.set_insoluble();
554  } else {
555  result.set_parens_off(start,size_t(chew));
556  if (result.net_infix_ops() < 2) {
557  delete_paren(start,size_t(chew));
558  }
559  }
560  chew(+1,greyspace);
561  break;
562  }
563  if (*chew == '+') {
564  chew(+1,greyspace);
565  result = unary_op(chew,end);
566  if (result.net_infix_ops() > 0) {
567  restore_paren(result.lparen_off(),result.rparen_off());
568  }
569  break;
570  }
571  if (*chew == '-') {
572  chew(+1,greyspace);
573  result = unary_op(chew,end);
574  if (result.net_infix_ops() > 0) {
575  restore_paren(result.lparen_off(),result.rparen_off());
576  break;
577  }
578  result.set_value(-result.value());
579  break;
580  }
581  if (isdigit(*chew)) {
582  size_t mark = size_t(chew);
584  if (val.type() != INT_UNDEF) {
585  if (identifier::is_start_char(*chew)) {
586  // Disallow UD-suffix in directive
587  chew = mark;
588  } else {
589  result.set_value(val);
590  }
591  }
592  break;
593  }
594  size_t mark = size_t(chew);
595  string word = canonical<symbol>(chew);
596  if (word == TOK_DEFINED) {
597  bool paren;
598  chew(greyspace);
599  paren = *chew == '(';
600  if (paren) {
601  chew(+1,greyspace);
602  }
603  symbol::locator sloc(chew);
604  chew(greyspace);
605  if (paren) {
606  if (*chew == ')') {
607  chew(+1,greyspace);
608  } else {
609  /* Missing ')'*/
610  error_unbalanced_paren() << "Expected \")\" after \""
611  << citable(!options::plaintext(),_seq.substr(0,size_t(chew)))
612  << "\" in \""
613  << citable(!options::plaintext(),_seq) << '\"' << defer();
614  result.set_insoluble();
615  }
616  }
617  sloc->report();
618  if (!sloc->configured()) {
619  if (options::implicit()) {
620  result.set_value(0);
621  }
622  break;
623  }
624  result.set_value(sloc->defined());
625  break;
626  } else if (word == TOK_ALT_BOOLEAN_NOT) {
627  chew(+1,greyspace);
628  result = unary_op(chew,end);
629  if (result.net_infix_ops() > 0) {
630  restore_paren(result.lparen_off(),result.rparen_off());
631  break;
632  }
633  result.set_value(!result.value());
634  break;
635  } else if (word == TOK_ALT_BIT_NOT) {
636  chew(+1,greyspace);
637  result = unary_op(chew,end);
638  if (result.net_infix_ops() > 0) {
639  restore_paren(result.lparen_off(),result.rparen_off());
640  break;
641  }
642  result.set_value(~result.value());
643  break;
644  }
645  else {
646  chew = mark;
647  }
648  if (*chew == '\'') {
649  /* Possible character constant */
650  size_t mark = size_t(chew);
652  if (val.type() != INT_UNDEF) {
653  if (identifier::is_start_char(*chew)) {
654  // Disallow UD-suffix in directive
655  chew = mark;
656  } else {
657  /* Got a character constant */
658  result.set_value(val);
659  }
660  break;
661  }
662  } else if (identifier::is_start_char(*chew)) {
663  size_t mark = size_t(chew);
664  if (*chew == 'L' || *chew == 'u' || *chew == 'U') {
665  /* Possible prefixed character constant*/
667  if (val.type() != INT_UNDEF) {
668  if (identifier::is_start_char(*chew)) {
669  // Disallow UD-suffix in directive
670  chew = mark;
671  } else {
672  /* Got a character constant */
673  result.set_value(val);
674  }
675  break;
676  }
677  }
678  if (identifier::is_start_char(*chew)) {
679  string id = identifier::read(chew);
680  symbol::locator sloc = symbol::lookup(id);
681  if (!sloc->configured()) {
682  sloc = symbol::locator(id);
683  argument_list args(chew);
684  if (!sloc->invoked() && args) {
685  sloc->set_parameters(args.size());
686  }
687  reference ref(sloc,args,_ref);
688  if (!ref.eval().insoluble() && !ref.args() &&
689  options::implicit()) {
690  result.set_value(0);
691  }
692  ref.report();
693  } else {
694  reference ref(sloc,chew,_ref);
695  ref.report();
696  result = ref.eval();
697  if (sloc->self_referential() || sloc->variadic()) {
698  break;
699  }
700  if (sloc->defined() && sloc->defn()->empty()) {
701  error_empty_symbol gripe;
702  gripe << '\"' << ref.invocation()
703  << "\" expands to nothing within expression";
704  defer_diagnostic(gripe);
705  } else if (result.insoluble()) {
706  if (ref.complete()) {
707  error_non_term gripe;
708  gripe << '\"' << ref.invocation()
709  << "\" expands to non-expression >>"
710  << ref.expansion() << "<< within expression";
711  defer_diagnostic(gripe);
712  } else {
714  gripe << "Macro expansion of \""
715  << ref.invocation()
716  << "\" abandoned. "
717  "Will exceed max expansion size "
719  << " bytes";
720  defer_diagnostic(gripe);
721  }
722  }
723  }
724  break;
725  }
726  }
727  else {
729  string good =
730  citable(!options::plaintext(),_seq.substr(0,size_t(chew)));
731  string bad =
732  citable(!options::plaintext(),_seq.substr(size_t(chew)));
733  gripe << "Ill-formed \"" << bad;
734  if (!good.empty()) {
735  gripe << "\" after \"" << good << '\"';
736  }
737  defer_diagnostic(gripe);
738  }
739 
740  } while(false);
741  return result;
742 }
743 template<class CharSeq>
745 {
747  _eval = infix_op<max>(chew,size_t(-1));
748  bool orphan_if = false;
749  if (_ternary_cond_stack.size()) {
750  orphan_if = true;
751  }
752  chew(greyspace);
753  if ((chew || orphan_if)) {
754  _eval.set_insoluble();
755  std::shared_ptr<diagnostic_base> gripe;
756  if (orphan_if) {
757  gripe.reset(new error_ternary_cond_incomplete);
758  *gripe
759  << "'?' of ternary conditional without following ':' "
760  "in \"" << citable(!options::plaintext(),_seq) << '\"';
761  } else {
762  string good =
763  citable(!options::plaintext(),_seq.substr(0,size_t(chew)));
764  string bad =
765  citable(!options::plaintext(),_seq.substr(size_t(chew)));
766  gripe.reset(new error_ill_formed_expression);
767  *gripe << "Ill-formed \"" << bad << "\" after \""
768  << good << '\"';
769  }
770 
771  if (!_ref) {
772  *gripe << " in \"" + line_despatch::pretty() + '\"';
773  }
774  *gripe << defer();
775  }
776  if (_cuts == 0) {
777  restore_paren();
778  }
779  if (!_ref) {
781  }
782 }
783 
784 template
786 template
788 
789 template<class CharSeq>
791 {
792  string const & in = _seq.str();
793  if (is_simplified()) {
794  string out;
795  size_t i = 0;
796  for ( ; i < _start; ++i) {
797  out += in[i];
798  }
799  if (i > 0 && _deletions[i] && isgraph(in[i - 1])) {
800  out += ' ';
801  ++i;
802  }
803  for ( ; ptrdiff_t(i) <= _last_deletion; ++i) {
804  if (!_deletions[i]) {
805  out += in[i];
806  }
807  }
808  if (i + 1 < _seq.size()) {
809  out += _seq.substr(i);
810  }
811  return out;
812  }
813  return in;
814 }
815 
816 template
818 
819 template<class CharSeq>
821  CharSeq & seq,
822  reference const * ref,
823  size_t start)
824 : _ternary_cond_stack(0),_seq(seq),_start(start),
825  _cuts(0),_last_deletion(-1),_ref(ref)
826 {
827  chewer<CharSeq> chew(!options::plaintext(),_seq,start);
828  parse(chew);
829 }
830 
832 
833 /* EOF*/
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.
Definition: diagnostic.h:764
template struct traits::is_random_access_char_sequence<T> exports a static const boolean member value...
Definition: traits.h:166
static bool plaintext()
Are we to omit parsing for C/C++ comments?
Definition: options.h:183
static bool implicit()
Do we implicitly --undef all unconfigured symbols?
Definition: options.h:195
evaluation op_rshift(evaluation const &lhs, evaluation const &rhs)
Right-shift operator.
template struct warning_msg<Id> generically encapsulates a warning diagnostic.
Definition: diagnostic.h:473
unsigned long long raw() const
Get the bits comprising the integer as an unsigned long long
Definition: integer.h:93
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.
Definition: identifier.h:52
template struct error_msg<Id> generically encapsulates an error diagnostic.
Definition: diagnostic.h:495
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.
Definition: symbol.h:194
integer const & value() const
Get the integral value of the expression.
Definition: evaluation.h:98
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.
Definition: symbol.h:274
evaluation op_ne(evaluation const &lhs, evaluation const &rhs)
Inequality operator.
struct symbol::locator encapsulates a symbol table entry.
Definition: symbol.h:79
bool good() const
Say whether the integer is of valid type, not INT_UNDEF
Definition: integer.h:81
void set_parens_off(size_t loff, size_t roff)
Set the text offsets of surrounding parentheses.
Definition: evaluation.h:126
#define TOK_ALT_BIT_NOT
Constant denoting the alternative bitwise negation operator.
Definition: lexicon.h:74
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.
Definition: evaluation.h:138
A base class for diagnostic classes.
Definition: diagnostic.h:85
#define TOK_DEFINED
Constant denoting the defined operator.
Definition: lexicon.h:70
bool configured() const
Say whether the symbol is configured.
Definition: symbol.h:258
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.
Definition: evaluation.h:115
Undetermined type or invalid.
Definition: integer.h:49
Class argument_list encapsulates a list of macro arguments, i.e. the arguments to a macro reference...
Definition: argument_list.h:50
evaluation op_ge(evaluation const &lhs, evaluation const &rhs)
Greater-than-or-equal operator.
Class integer encapsulates an integer of some type.
Definition: integer.h:65
warning_msg< 14 > warning_zero_divide
Report a divide by zero was found in an expression.
Definition: diagnostic.h:675
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.
Definition: symbol.h:396
void set_value(integer const &val)
Set the integral value of the expression.
Definition: evaluation.h:103
bool variadic() const
Say whether this symbol is a variadic macro.
Definition: symbol.h:321
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.
Definition: evaluation.h:143
std::string read(chewer< CharSeq > &chew)
Read an identifier from an chewer<CharSeq>
bool defined() const
Is the symbol defined.
Definition: symbol.h:213
static size_t flush(unsigned reason)
Emit all queued diagnostics that match a reason-code.
Definition: diagnostic.h:237
chew_mode::continuation const continuation
An exemplar chew_mode::continuation
Definition: chew.h:213
evaluation op_mult(evaluation const &lhs, evaluation const &rhs)
Multiplication operator.
error_msg< 14 > error_unbalanced_paren
Report unbalanced parenthesis.
Definition: diagnostic.h:752
The tag class is inserted in a diagnostic_base to tell it to emit itself.
Definition: diagnostic.h:77
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
Definition: chew.h:211
bool resolved() const
Say whether the expression has been resolved.
Definition: evaluation.h:65
The tag class is inserted in a diagnostic_base to tell it to defer itself.
Definition: diagnostic.h:82
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.
Definition: identifier.h:57
integer_type type() const
Get the type of the integer
Definition: integer.h:77
evaluation op_bit_or(evaluation const &lhs, evaluation const &rhs)
Bitwise OR operator.
An error diagnostic.
static constexpr unsigned max_expansion_size()
Cut-off size for macro-expansions.
void set_parameters(formal_parameter_list const &params)
Set a macro parameter list for the symbol.
Definition: symbol.h:221
`template struct chewer<CharSeq> is a cursor-like type that is associated with a character-sequence t...
Definition: chew.h:248
template class canonical<What> encapsulates the canonical representation of values of type What...
Definition: canonical.h:82
bool insoluble() const
Say whether the expression is insoluble.
Definition: evaluation.h:80
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.
Definition: evaluation.h:75
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.
Definition: lexicon.h:72
static std::string pretty()
Get a pretty printable version of the current input line.
bool is_true() const
Say whether the expression is true.
Definition: evaluation.h:70
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.
Definition: symbol.h:279
struct evaluation represents the result of evaluating a putative expression.
Definition: evaluation.h:48
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.
Definition: evaluation.h:93