coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
reference.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 
41 #include "reference.h"
42 #include "expansion_base.h"
43 #include "options.h"
44 #include "io.h"
45 #include "expression_parser.h"
46 #include "diagnostic.h"
47 #include "citable.h"
48 #include "options.h"
49 #include "line_despatch.h"
50 #include <iostream>
51 
52 using namespace std;
53 
54 bool reference::explaining() const {
55  if (!_invoker) {
56  return
59  (_referee->in_progress() || _referee->invoked()) &&
60  !_referee->deselected() &&
61  !_referee->self_referential();
62  }
63  return _invoker->explaining();
64 }
65 
68  reference_cache::iterator loc = lower_bound();
69  if (reference_cache::at_end(loc) || loc->first != _key) {
70  reference_cache::value_type v = digest();
71  if (!_referee->self_referential()) {
72  _referee->make_clean();
73  }
74  return insert_result(reference_cache::insert(v,loc),true);
75  }
76  if (_referee->dirty()) {
77  loc->second = digest().second;
78  if (!_referee->self_referential()) {
79  _referee->make_clean();
80  }
81  return insert_result(loc,true);
82  }
83  return insert_result(loc,false);
84 }
85 
87 {
88  bool exp = explain();
89  if (exp) {
90  unsigned lineno = line_despatch::cur_line().num();
91  cout << "Expanding \"" << invocation();
92  if (lineno) {
93  cout << "\" at " << io::in_file_name() << '(' << lineno << ")\n";
94  } else {
95  cout << " in options\n";
96  }
97  }
98  reference_cache::entry resolved = expand(exp);
99  if (!resolved.eval().insoluble() && !resolved.eval().empty()) {
100  string & s = const_cast<string &>(resolved.expansion());
101  chewer<string> chew(chew_mode::plaintext,s);
102  chew(string_literal); // Expands as string literal?
103  if (size_t(chew) == 0) {
104  chew(header_name); // Expands as header name?
105  }
106  if (size_t(chew) == 0) {
107  resolved.eval() = evaluation(expression_parser<string>(chew,this));
108  } else {
109  resolved.eval().set_insoluble();
110  }
111  }
112  return reference_cache::value_type(_key,resolved);
113 }
114 
116 {
117  evaluation eval = validate();
118  if (eval.insoluble()) {
119  return reference_cache::entry(invocation(),eval);
120  }
121  if (eval.empty()) {
122  return reference_cache::entry(string(),eval);
123  }
124  unique_ptr<expansion_base> pe = expansion_base::factory(explain,*this);
125  try {
126  pe->expand();
127  }
128  catch(expansion_base const & eb) {
129  eval.set_insoluble();
130  return reference_cache::entry(
131  pe->reference::invocation(),eval,false,false);
132  }
133  return reference_cache::entry(pe->value(),eval,false,true);
134 }
135 
136 
137 bool reference::reportable() const {
138  return (options::get_command() == CMD_SYMBOLS &&
139  line_despatch::cur_line().reportable() &&
140  !_referee->deselected() &&
141  (!_invoker || _referee->configured()));
142 }
143 
145 {
146  insert_result result = lookup();
147  bool clean = result.second;
148  reference_cache::entry & entry = result.first->second;
150  return;
151  }
152  entry.set_reported();
153  bool lineno = line_despatch::cur_line().num();
154  char const * adverb = (clean || lineno == 0) ? "afresh " : "unchanged ";
155  cout << invocation();
156  switch(_referee->origin()) {
158  cout << ": unconfigured";
159  break;
161  cout << ": global";
162  break;
164  cout << ": transient";
165  break;
166  default:
167  assert(false);
168  }
171  if (_referee->defn()) {
172  cout << ": def. >>";
173  if (_referee->parameters()) {
174  cout << _referee->signature() << '=';
175  }
176  cout << *_referee->defn() << "<<";
177  } else {
178  cout << ": undef";
179  }
180  }
181  if(_referee->configured()) {
182  if (_referee->parameters().variadic()) {
183  cout << ": insoluble, because variadic macro parameters "
184  "are unsupported";
185  } else {
186  if (_referee->self_referential()) {
187  cout << ": insoluble, because of infinite regress";
188  } else if (entry.complete()) {
189  cout << ": expands " << adverb
190  << "as >>" + entry.expansion() + "<<";
191  if (entry.eval().resolved()) {
192  cout << ": evaluates to "
193  << citable(entry.eval().value());
194  }
195  } else {
196  cout << ": insoluble, because macro expansion too large";
197  }
198  }
199  } else {
200  cout << ": insoluble";
201  }
202  }
203  if (lineno == 0) {
204  cout << ": in options";
205  } else if (options::list_location()) {
206  cout << ": " << io::in_file_name()
207  << "(" << line_despatch::cur_line().num() << ")";
208  }
209  cout << '\n';
210 }
211 
213 {
214  evaluation eval;
215  if (!_args.well_formed()) {
217  "Malformed argument list for \""
218  << invocation() << "\"" << emit();
219  eval.set_insoluble();
220  } else if (_referee->self_referential()) {
221  warning_infinite_regress() << "Infinite regress in expansion of \""
222  << invocation() << '\"' << emit();
223  eval.set_insoluble();
224  } else if (_referee->parameters().variadic()) {
226  "Sorry, variadic macro expansion is unsupported. "
227  << "\"" << invocation() << "\"" <<
228  " will not be resolved" << emit();
229  eval.set_insoluble();
230  } else if (_args.size() != _referee->parameters().size()) {
231  if (_referee->configured()) {
233  << '\"' << _referee->signature()
234  << "\" takes " << _referee->parameters().size()
235  << " arguments; " << _args.size() << " provided" << emit();
236  } else if (_referee->invoked()){
238  << "Unconfigured symbol \"" << _referee->id()
239  << "\" has already taken " << _referee->parameters().size()
240  << " arguments; " << _args.size() << " provided" << emit();
241  }
242  eval.set_insoluble();
243  } else if (!_referee->configured()) {
244  if (options::implicit()) {
245  if (_args) {
247  << "Function-like invocation of undefined symbol: \""
248  << invocation() << "\" (option --implicit)" << emit();
249  eval.set_insoluble();
250  }
251  } else {
252  eval.set_insoluble();
253  }
254  } else if (_referee->defn() && _referee->defn()->empty()) {
255  eval.set_empty();
256  }
257  return eval;
258 }
259 
260 // EOF
261 
static parsed_line & cur_line()
Get a reference to the current output line.
Definition: line_despatch.h:68
static iterator insert(value_type const &v, iterator hint)
Insert a value_type into the cache.
static bool implicit()
Do we implicitly --undef all unconfigured symbols?
Definition: options.h:195
error_msg< 18 > error_mismatched_macro_args
Report wrong number of macro arguments for symbol.
Definition: diagnostic.h:760
error_msg< 17 > error_malformed_macro
Report a malformed macro parameter list.
Definition: diagnostic.h:758
void do_report()
Do reporting of the reference if reportable.
Definition: reference.cpp:144
static bool at_end(Iter i)
Say whether an iterator points to the end of the cache.
void set_reported(bool value=true)
Mark the entry as reported, or not.
The symbols command.
Definition: options.h:76
The symbol is globally configured by a commandline option.
integer const & value() const
Get the integral value of the expression.
Definition: evaluation.h:98
warning_msg< 34 > warning_inconsistent_calls
Report inconsistent argument lists for unconfigured symbol references.
Definition: diagnostic.h:719
warning_msg< 12 > warning_infinite_regress
Report a symbol has a circular definition.
Definition: diagnostic.h:671
static command_code get_command()
Get the operative coan command code.
Definition: options.cpp:247
Encapsulates parsing of preprocessor expressions.
map::iterator iterator
Iterator type on map
map::value_type value_type
Value-type of map
The symbol is not configured.
chew_mode::string_literal const string_literal
An exemplar chew_mode::string_literal
Definition: chew.h:219
void set_insoluble()
Classify the expression as insoluble.
Definition: evaluation.h:115
bool reportable() const
Say whether this reference is eligible for reporting.
Definition: reference.cpp:137
reference_cache::insert_result lookup()
Lookup the reference in the cache.
Definition: reference.cpp:67
error_msg< 19 > error_macro_call_on_undefined
Report attempting macro-ref on undefined symbol.
Definition: diagnostic.h:762
static bool explain_references()
Do we report the progressive expansion of symbol references?
Definition: options.h:205
reference_cache::insert_result insert_result
Type of result from cache insertion.
Definition: reference.h:59
static std::string in_file_name()
Get the name of the current source file.
Definition: io.h:105
std::string citable(chewer< std::string > &chew, size_t len=std::string::npos)
Make a citable version of length-delimited text.
void set_empty()
Classify the expression as empty.
Definition: evaluation.h:121
unsigned num() const
Get the greatest source line number spanned by this line.
Definition: parsed_line.h:70
reference_cache::value_type digest()
Return a cache entry for this reference.
Definition: reference.cpp:86
reference_cache::entry expand(bool explain)
Expand the reference.
Definition: reference.cpp:115
evaluation const & eval() const
Get a [const] reference to the evaluation of the cached reference.
static bool list_at_most_once_per_file()
Say whether items are reportable at most once per file.
Definition: options.h:225
std::string const & expansion() const
Get the expansion of the cached reference.
static bool expand_references()
Do we report the expansions reported symbols?
Definition: options.h:171
The tag class is inserted in a diagnostic_base to tell it to emit itself.
Definition: diagnostic.h:77
static std::unique_ptr< expansion_base > factory(bool explain, reference const &ref)
Global factory of subclasses of expansion_base
bool resolved() const
Say whether the expression has been resolved.
Definition: evaluation.h:65
static bool list_location()
Do we report file and line numbers for listed items?
Definition: options.h:113
warning_msg< 26 > warning_variadic_macros_unsupported
Apologize that variadic macro expansion is unsupported.
Definition: diagnostic.h:701
chew_mode::header_name const header_name
An exemplar chew_mode::header_name
Definition: chew.h:225
The symbol is transiently configured by an in-source directive.
bool reportable()
Is the line reportable for the operative command.
Definition: parsed_line.h:127
`template struct chewer<CharSeq> is a cursor-like type that is associated with a character-sequence t...
Definition: chew.h:248
bool insoluble() const
Say whether the expression is insoluble.
Definition: evaluation.h:80
evaluation validate() const
Diagnose a syntactically invalid reference.
Definition: reference.cpp:212
struct expansion_base is an abstract base for classes that encapsulate a mode of macro-expansion of a...
Encapsulates an entry in the reference cache.
bool empty() const
Say whether the expression is empty.
Definition: evaluation.h:85
bool complete() const
Is the cached reference fully expanded?
struct evaluation represents the result of evaluating a putative expression.
Definition: evaluation.h:48
bool reported() const
Has the cached reference been reported.
bool explaining() const
Say whether this reference is to be explained or is descended from one being explained.
Definition: reference.cpp:54