--- /dev/null
+#include <iostream.h>
+#include <memory.h>
+#include <CxxToken.hxx>
+
+extern CxxToken *yylex_token();
+
+#ifdef BISON_PP_CLASS
+BISON_PP_CLASS theParser;
+#define PARSE_DOT theParser .
+#define PARSE_SCOPE BISON_PP_CLASS ::
+#else
+#define PARSE_DOT
+#define PARSE_SCOPE
+extern int yydebug;
+#ifndef YYEMPTY
+#define YYEMPTY -1
+#endif
+#endif
+
+class CxxSearchContext
+{
+ friend class ios; // Suppress GNU error message for no public constructors.
+ CxxSearchContext *_next;
+ size_t _index;
+ size_t _depth;
+ size_t _size;
+ size_t _mark;
+ bool _enable_type1;
+ size_t _line;
+ size_t _advances;
+ bool _status[32];
+private:
+ CxxSearchContext(CxxSearchContext *nextSearch)
+ : _next(nextSearch), _index(0), _depth(0), _size(sizeof(_status)/sizeof(_status[0])),
+ _mark(0), _enable_type1(false), _line(0), _advances(0) {}
+ CxxSearchContext(const CxxSearchContext&);
+ CxxSearchContext& operator=(const CxxSearchContext&);
+ bool did_search() const { return _depth > 0 ? true : false; }
+ void initialise(size_t markIndex, bool enableType1);
+ CxxSearchContext *queue(CxxSearchContext *& listHead);
+ void reset();
+public:
+ bool advance();
+ bool enable_type1() const { return _enable_type1; }
+ bool is_template();
+ size_t mark() const { return _mark; }
+private:
+ static CxxSearchContext *_current;
+ static CxxSearchContext *_free;
+public:
+ static size_t actual_searches;
+ static size_t advances[16];
+ static size_t max_search_depth;
+ static size_t nested_searches;
+ static size_t releases;
+ static size_t search_advances;
+ static size_t unnested_searches;
+public:
+ static CxxSearchContext *current() { return _current; }
+ static void release();
+ static void start(YACC_MARK_TYPE anIndex, bool enableType1);
+};
+
+size_t bang_depth = 0;
+size_t error_count = 0;
+size_t marked_error_count = 0;
+bool in_type1 = false;
+bool show_marked = false;
+
+int main(int argc, char *argv[])
+{
+ for (--argc, ++argv; argc-- > 0; ++argv)
+ {
+ char *p = *argv;
+ if (*p == '-')
+ {
+ switch (*(p+1))
+ {
+ case 'c':
+ c_keywords = true;
+ break;
+ case 't':
+ echo_line_text = true;
+ break;
+ case 'm':
+ show_marked = true;
+ break;
+ case 'n':
+ echo_line_numbers = true;
+ break;
+ case 'y':
+ PARSE_DOT yydebug = true;
+ break;
+ }
+ }
+ }
+ if (PARSE_DOT yyparse() != 0)
+ ERRMSG("Failed to parse to end of file,");
+ cout << "error_count = " << error_count
+ << ", marked_error_count = " << marked_error_count
+ << ", lines = " << line_number
+ << ", unnested_searches = " << CxxSearchContext::unnested_searches
+ << ", nested_searches = " << CxxSearchContext::nested_searches
+ << ", releases = " << CxxSearchContext::releases
+ << ", actual_searches = " << CxxSearchContext::actual_searches
+ << ", max_search_depth = " << CxxSearchContext::max_search_depth
+ << ", search_advances = " << CxxSearchContext::search_advances << endl;
+ cout << "number of occurences of each advance";
+ for (size_t i = 0; i < sizeof(CxxSearchContext::advances)/sizeof(CxxSearchContext::advances[0]); i++)
+ cout << ' ' << CxxSearchContext::advances[i];
+ cout << endl;
+ return 0;
+}
+
+static CxxToken **tokenBuffer = 0; // Allocated buffer
+static YACC_MARK_TYPE tokenReadIndex = 0; // Read index
+static size_t tokenSize = 0; // Allocate buffer size
+static YACC_MARK_TYPE tokenWriteIndex = 0; // Write index
+int tokenMarkDepth = 0; // Write index
+static CxxToken *primed_tokens[3] = {0, 0}; // Restarting sequence
+static void token_put(CxxToken *aToken);
+
+CxxSearchContext *CxxSearchContext::_current = 0;
+CxxSearchContext *CxxSearchContext::_free = 0;
+size_t CxxSearchContext::actual_searches = 0;
+size_t CxxSearchContext::advances[16] = { 0 };
+size_t CxxSearchContext::max_search_depth = 0;
+size_t CxxSearchContext::nested_searches = 0;
+size_t CxxSearchContext::releases = 0;
+size_t CxxSearchContext::search_advances;
+size_t CxxSearchContext::unnested_searches;
+
+//
+// Implements a binary search counter, performing the increment at the
+// _index of othe failed search.
+//
+bool CxxSearchContext::advance()
+{
+ _advances++;
+ size_t i = _depth;
+ if (i <= 0)
+ return false;
+ while (--i > _index)
+ _status[i] = false;
+ while (true)
+ {
+ if (!_status[i])
+ {
+ _status[i] = true;
+ _index = 0;
+ return true;
+ }
+ if (i <= 0)
+ return false;
+ _status[i--] = false;
+ }
+}
+
+void CxxSearchContext::initialise(size_t markIndex, bool enableType1)
+{
+ _index = 0;
+ _depth = 0;
+ _mark = markIndex;
+ _enable_type1 = enableType1;
+ _line = line_number;
+ _advances = 0;
+}
+
+bool CxxSearchContext::is_template()
+{
+ if (_index >= _depth)
+ {
+ if (_depth >= _size)
+ {
+ ERRMSG("Binary search depth exceeded.");
+ return false;
+ }
+ _status[_depth++] = false;
+ if (_depth > max_search_depth)
+ max_search_depth = _depth;
+ }
+ return _status[_index++] ? false : true;
+}
+
+//
+// Put this element onto listHead, returning element under this one.
+//
+CxxSearchContext *CxxSearchContext::queue(CxxSearchContext *& listHead)
+{
+ CxxSearchContext *oldNext = _next;
+ _next = listHead;
+ listHead = this;
+ return oldNext;
+}
+
+//
+// Release the current search buffer.
+//
+void CxxSearchContext::release()
+{
+ if (_current)
+ {
+ releases++;
+ _current->reset();
+ _current = _current->queue(_free);
+ }
+}
+
+void CxxSearchContext::reset()
+{
+ if (did_search())
+ {
+ _advances++;
+ actual_searches++;
+ }
+ if (_advances >= sizeof(advances)/sizeof(advances[0]))
+ advances[sizeof(advances)/sizeof(advances[0])-1]++;
+ else
+ advances[_advances]++;
+}
+
+void CxxSearchContext::start(YACC_MARK_TYPE anIndex, bool enableType1)
+{
+ if (!_current)
+ unnested_searches++;
+ else
+ nested_searches++;
+ if (!_free)
+ _current = new CxxSearchContext(_current);
+ else
+ _free = _free->queue(_current);
+ _current->initialise(anIndex, enableType1);
+}
+
+static CxxToken angleToken('<');
+static CxxToken colonToken(':');
+static CxxToken hashToken('#');
+static CxxToken plusToken('+');
+static CxxToken minusToken('-');
+
+void PARSE_SCOPE yyerror(const char *s)
+{
+ if (!bang_depth && (tokenMarkDepth == 0))
+ {
+ cout << s << endl;
+ increment_error_count();
+ }
+ else
+ {
+ if (show_marked)
+ cout << "Marked " << s << endl;
+ marked_error_count++;
+ }
+}
+
+//
+// Get the next token for the parser, invoking yylex_token to get the next token from the lexer.
+// This routine gets renamed to buffered_yylex by a #define when using yacc so that the two purposes
+// above are split allowing lookahead buffering and primimimg to occur.
+//
+int PARSE_SCOPE yylex()
+{
+ CxxToken *aToken = primed_tokens[0];
+ if (aToken)
+ {
+ primed_tokens[0] = primed_tokens[1];
+ primed_tokens[1] = primed_tokens[2];
+ primed_tokens[2] = 0;
+ }
+ else if (tokenReadIndex < tokenWriteIndex)
+ aToken = tokenBuffer[tokenReadIndex++];
+ else
+ {
+ aToken = yylex_token();
+ if (!aToken)
+ return 0;
+ if (tokenMarkDepth > 0)
+ token_put(aToken);
+ else
+ {
+ tokenWriteIndex = 0;
+ tokenReadIndex = 0;
+ }
+ }
+ yylval.token = aToken;
+ return aToken->value();
+}
+
+//
+// Advance the binary search of template attempts. Rewinds and forces true into the input sequence
+// to proceed with the search. Rewinds and forces false to terminate it. Also forces a # that may then
+// be used to initiate error propagation.
+//
+void advance_search()
+{
+ CxxSearchContext::search_advances++;
+ remark(CxxSearchContext::current()->mark());
+ if (CxxSearchContext::current() && CxxSearchContext::current()->advance())
+ {
+ primed_tokens[0] = &plusToken;
+ primed_tokens[1] = 0;
+ }
+ else
+ {
+ primed_tokens[0] = &minusToken;
+ primed_tokens[1] = &hashToken;
+ }
+}
+
+//
+// Complete a search, releasing the search context object and popping a mark off the stack.
+//
+void end_search(CxxToken *aToken)
+{
+ CxxSearchContext::release();
+ unmark(aToken);
+}
+
+//
+// Notch up an error and establish a good break point.
+//
+void increment_error_count()
+{
+ error_count++;
+}
+
+//
+// Push a new marked context onto the stack, returning its identity for use by remark().
+// Any parser readahead is incorporated within the marked region.
+//
+YACC_MARK_TYPE mark()
+{
+ if (primed_tokens[0])
+ ERRMSG("Unexpected primed_tokens[0] in mark.");
+ YACC_MARK_TYPE markIndex = tokenReadIndex;
+ if (PARSE_DOT yychar != YYEMPTY)
+ {
+// if (primed_tokens[2])
+// token_put(primed_tokens[2]);
+// if (primed_tokens[1])
+// token_put(primed_tokens[1]);
+// if (primed_tokens[0])
+// token_put(primed_tokens[0]);
+// if (!tokenMarkDepth)
+ if (!tokenReadIndex && !tokenWriteIndex)
+ {
+ token_put(PARSE_DOT yylval.token);
+ tokenReadIndex = 0;
+ }
+ else if (!tokenReadIndex)
+ ERRMSG("Unexpected 0 read index in mark.");
+ else if (tokenBuffer[--tokenReadIndex] != PARSE_DOT yylval.token)
+ ERRMSG("Unexpected unget in mark.");
+ markIndex = tokenReadIndex;
+ yyclearin;
+ primed_tokens[0] = 0;
+ primed_tokens[1] = 0;
+ }
+ tokenMarkDepth++;
+ bang_depth++;
+ return markIndex;
+}
+
+//
+// If it is appropriate to do type I function parameter parsing perform a mark and force a rrue token
+// into the input stream. Otherwise just force a false token in.
+//
+YACC_MARK_TYPE mark_type1()
+{
+ if (!in_type1 && CxxSearchContext::current() && CxxSearchContext::current()->enable_type1())
+ {
+ YACC_MARK_TYPE markIndex = mark();
+ primed_tokens[0] = &plusToken;
+ primed_tokens[1] = 0;
+ in_type1 = true;
+ yyclearin;
+ return markIndex;
+ }
+ else
+ {
+ primed_tokens[0] = &minusToken;
+ primed_tokens[1] = PARSE_DOT yychar != YYEMPTY ? PARSE_DOT yylval.token : 0;
+ yyclearin;
+ return 0; // Never used.
+ }
+}
+
+//
+// Push a bang context onto the error suppression stack, returning the context for restoration by pop_bang.
+//
+void pop_bang(YACC_BANG_TYPE bangValue)
+{
+ bang_depth = bangValue;
+}
+
+//
+// Push a bang context onto the error suppression stack, returning the context for restoration by pop_bang.
+//
+YACC_BANG_TYPE push_bang()
+{
+ return bang_depth++;
+}
+
+//
+// Reposition the input to restart at the position returned by a mark().
+//
+void remark(YACC_MARK_TYPE anIndex)
+{
+ tokenReadIndex = anIndex;
+ yyclearin;
+}
+
+//
+// Reposition the input to restart at the position returned by a mark().
+//
+void remark_type1(YACC_MARK_TYPE anIndex)
+{
+ remark(anIndex);
+ in_type1 = false;
+}
+
+//
+// Rewind the input stream back to anIndex and force a : prior to resuming input.
+//
+void rewind_colon(YACC_MARK_TYPE anIndex, const CxxToken *aToken)
+{
+ remark(anIndex);
+ unmark();
+ primed_tokens[0] = &colonToken;
+ primed_tokens[1] = PARSE_DOT yylval.token;
+}
+
+//
+// Start a new binary search over the template/arithmetic alternative parses of a statement.
+// Marks the current position and saves it in a binary search context maintained on a private stack.
+//
+void start_search(bool enableType1)
+{
+ bool type1Enabled = !CxxSearchContext::current() || CxxSearchContext::current()->enable_type1() ? true : false;
+ CxxSearchContext::start(mark(), enableType1 && type1Enabled ? true : false);
+}
+
+//
+// Determine whether the just parsed < should be interpreted as a template or arithmetic operator.
+// The implementation here intersacts with a binary search to traverse all possibilities in
+// multiple passes. The search proceeds by branch and bound presuming the template interpretation.
+// A true token is forced into the input stream to take the template interpretaion. A false token
+// otherwise.
+//
+// An alternate implementation that keeps track of scopes may interact with semantic knowledge to make
+// the correct decision directly.
+//
+void template_test()
+{
+ if (!CxxSearchContext::current() || CxxSearchContext::current()->is_template())
+ {
+ primed_tokens[0] = &plusToken;
+ primed_tokens[1] = 0;
+ }
+ else
+ {
+ primed_tokens[0] = &minusToken;
+ primed_tokens[1] = &angleToken;
+ }
+}
+
+void token_put(CxxToken *aToken)
+{
+ if (!tokenBuffer || !tokenSize)
+ tokenBuffer = new CxxToken *[tokenSize = 256];
+ else if (tokenWriteIndex >= tokenSize)
+ {
+ CxxToken **oldTokenBuffer = tokenBuffer;
+ size_t oldTokenSize = tokenSize;
+ tokenBuffer = new CxxToken *[tokenSize *= 2];
+ memcpy(tokenBuffer, oldTokenBuffer, oldTokenSize * sizeof(*oldTokenBuffer));
+ delete[] oldTokenBuffer;
+ }
+ tokenBuffer[tokenWriteIndex++] = aToken;
+ tokenReadIndex = tokenWriteIndex;
+}
+
+//
+// Pop a marked context off the stack.
+//
+void unmark(const CxxToken *aToken)
+{
+ if (bang_depth)
+ bang_depth--;
+ else
+ ERRMSG("BUG - should not unmark with 0 bang.");
+ if (tokenMarkDepth <= 0)
+ ERRMSG("Unexpected unmark.");
+ else
+ tokenMarkDepth--;
+}