sustaining_gazes/lib/3rdParty/dlib/include/dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h

584 lines
20 KiB
C++

// Copyright (C) 2005 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_1_
#define DLIB_CPP_PRETTY_PRINTER_KERNEl_1_
#include <string>
#include <iostream>
#include <sstream>
#include "cpp_pretty_printer_kernel_abstract.h"
#include "../algs.h"
namespace dlib
{
template <
typename stack,
typename tok
>
class cpp_pretty_printer_kernel_1
{
/*!
REQUIREMENTS ON stack
must be an implementation of stack/stack_kernel_abstract.h and
stack::type == unsigned long
REQUIREMENTS ON tok
must be an implementation of tokenizer/tokenizer_kernel_abstract.h
INFO
This implementation applies a color scheme, turns include directives
such as #include "file.h" into links to file.h.html, and it also puts
HTML anchor points on function and class declarations.
!*/
public:
cpp_pretty_printer_kernel_1 (
);
virtual ~cpp_pretty_printer_kernel_1 (
);
void print (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
void print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const;
private:
const std::string htmlify (
const std::string& str
) const;
/*!
ensures
- str == str but with any '<' replaced with '&lt;', any '>' replaced
with '&gt;', and any '&' replaced with '&amp;'
!*/
// data members
mutable tok t;
void number (
std::istream& in,
std::ostream& out
) const;
/*!
ensures
- prints in to out and adds line numbers
!*/
// restricted functions
cpp_pretty_printer_kernel_1(const cpp_pretty_printer_kernel_1&); // copy constructor
cpp_pretty_printer_kernel_1& operator=(const cpp_pretty_printer_kernel_1&); // assignment operator
};
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
cpp_pretty_printer_kernel_1<stack,tok>::
cpp_pretty_printer_kernel_1 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
cpp_pretty_printer_kernel_1<stack,tok>::
~cpp_pretty_printer_kernel_1 (
)
{
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_1<stack,tok>::
print (
std::istream& in,
std::ostream& out,
const std::string& title
) const
{
using namespace std;
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
t.set_stream(in);
out << "<html><!-- "
<< "Created using the cpp_pretty_printer from the dlib C++ library. See http://dlib.net for updates."
<< " --><head><title>" << title << "</title></head><body bgcolor='white'><pre>\n";
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
unsigned long scope = 0; // counts the number of new scopes we have entered
// since we were at a scope where functions can be declared
bool recently_seen_class_keyword = false;
// true if we have seen the keywords class, struct, or enum and
// we have not seen any identifiers or { characters
bool recently_seen_include = false;
// true if we have seen the #include keyword and have not seen double
// quoted text or >
bool recently_seen_new_scope = false;
// true if we have seen the keywords class, namespace, or struct and
// we have not seen the characters {, ), or ; since then
bool recently_seen_paren = false;
// true if we have seen a ) and we have only seen white_space or comments since
bool in_initialization_list = false;
// true if we have seen a ) followed by any white space or comments and then
// followed by a : (in scope==0 with recently_seen_preprocessor==false) and we
// have not yet seen the character { or ;
bool recently_seen_preprocessor = false;
// true if we have seen the #pragma or #if or #define or #elif keywords and have
// not seen an end of line.
bool recently_seen_extern = false;
// true if we have seen the extern keyword and haven't seen a ; or { yet.
unsigned long paren_count = 0;
// this is the number of ( we have seen minus the number of ) we have
// seen.
int type;
stack scopes; // a stack to hold old scopes
string token, temp;
t.get_token(type,token);
while (type != tok::END_OF_FILE)
{
switch (type)
{
case tok::IDENTIFIER: // ------------------------------------------
if ( recently_seen_class_keyword)
{
// this might be a class name so check if there is a
// ; or identifier or * or & coming up.
type = t.peek_type();
temp.clear();
if (type == tok::WHITE_SPACE)
{
t.get_token(type,temp);
if (temp.find_first_of("\n\r") != string::npos)
recently_seen_preprocessor = false;
}
if (t.peek_token() != ";" && t.peek_type() != tok::IDENTIFIER &&
t.peek_token() != "*" && t.peek_token() != "&")
{
// this is the name of a class or struct in a class or
// struct declaration.
out << "<b><a name='" << token << "'></a>" << token << "</b>" << temp;
}
else
{
out << token << temp;
}
}
else if ( !in_initialization_list &&
!recently_seen_preprocessor )
{
// this might be a function name so check if there is a
// ( coming up.
type = t.peek_type();
temp.clear();
if (type == tok::WHITE_SPACE)
{
t.get_token(type,temp);
type = t.peek_type();
}
if (type == tok::OTHER && t.peek_token() == "(")
{
if (scope == 0 && paren_count == 0)
{
// this is a function definition or prototype
out << "<b><a name='" << token << "'></a>" << token << "</b>" << temp;
}
else
{
// this is a function call (probably)
out << "<font color='#BB00BB'>" << token << "</font>" << temp;
}
}
else
{
out << token << temp;
}
}
else
{
out << token;
}
recently_seen_class_keyword = false;
recently_seen_paren = false;
break;
case tok::KEYWORD: // ---------------------------------------------
if (scope == 0 && token == "operator")
{
// Doing this is sort of weird since operator is really a keyword
// but I just like how this looks.
out << "<b><a name='" << token << "'></a>" << token << "</b>";
}
// this isn't a keyword if it is something like #include <new>
else if ( token == "true" || token == "false")
{
// color 'true' and 'false' the same way we color numbers
out << "<font color='#979000'>" << token << "</font>";
}
else if (!recently_seen_include)
{
// This is a normal keyword
if (token == "char" || token == "unsigned" || token == "signed" ||
token == "short" || token == "int" || token == "long" ||
token == "float" || token == "double" || token == "bool" ||
token == "void" || token == "size_t" || token == "wchar_t")
{
out << "<font color='#0000FF'><u>" << token << "</u></font>";
}
else
{
out << "<font color='#0000FF'>" << token << "</font>";
}
}
else
{
out << token;
}
if (token == "#include")
{
recently_seen_include = true;
}
else if (token == "class")
{
recently_seen_new_scope = true;
recently_seen_class_keyword = true;
}
else if (token == "namespace")
{
recently_seen_new_scope = true;
}
else if (token == "enum")
{
recently_seen_class_keyword = true;
}
else if (token == "struct")
{
recently_seen_new_scope = true;
recently_seen_class_keyword = true;
}
else if (token == "#pragma" || token == "#if" || token == "#define" || token == "#elif")
{
recently_seen_preprocessor = true;
}
else if (token == "extern")
{
recently_seen_extern = true;
}
recently_seen_paren = false;
break;
case tok::COMMENT: // ---------------------------------------------
{
// if this is a special anchor comment
if (token.size() > 4 &&
token[0] == '/' &&
token[1] == '*' &&
token[2] == '!' &&
token[3] == 'A' &&
token[4] == ' '
)
{
temp = token;
istringstream sin(token);
sin >> temp;
sin >> temp;
sin.get();
// if there was still more stuff in the token then we are ok.
if (sin)
out << "<a name='" << temp << "'/>";
}
out << "<font color='#009900'>" << htmlify(token) << "</font>";
}
break;
case tok::SINGLE_QUOTED_TEXT: // ----------------------------------
{
out << "<font color='#FF0000'>" << htmlify(token) << "</font>";
recently_seen_paren = false;
}
break;
case tok::NUMBER: // -----------------------------------------
{
out << "<font color='#979000'>" << token << "</font>";
recently_seen_include = false;
}
break;
case tok::WHITE_SPACE: // -----------------------------------------
{
out << token;
if (token.find_first_of("\n\r") != string::npos)
recently_seen_preprocessor = false;
}
break;
case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------
{
if (recently_seen_include)
{
// this is the name of an included file
recently_seen_include = false;
out << "<a style='text-decoration:none' href='" << htmlify(token) << ".html'>" << htmlify(token) << "</a>";
}
else
{
// this is just a normal quoted string
out << "<font color='#CC0000'>" << htmlify(token) << "</font>";
}
recently_seen_paren = false;
}
break;
case tok::OTHER: // -----------------------------------------------
switch (token[0])
{
case '{':
out << "<b>{</b>";
// if we are entering a new scope
if (recently_seen_new_scope || recently_seen_extern)
{
recently_seen_new_scope = false;
scopes.push(scope);
scope = 0;
}
else
{
++scope;
}
in_initialization_list = false;
recently_seen_paren = false;
recently_seen_class_keyword = false;
recently_seen_extern = false;
break;
case '}':
out << "<b>}</b>";
if (scope > 0)
{
--scope;
}
else if (scopes.size())
{
scopes.pop(scope);
}
recently_seen_paren = false;
break;
case ':':
out << ':';
if (recently_seen_paren && scope == 0 &&
recently_seen_preprocessor == false)
{
in_initialization_list = true;
}
recently_seen_paren = false;
break;
case ';':
out << ';';
recently_seen_new_scope = false;
recently_seen_paren = false;
recently_seen_extern = false;
break;
case ')':
out << "<font face='Lucida Console'>)</font>";
recently_seen_paren = true;
recently_seen_new_scope = false;
--paren_count;
break;
case '(':
out << "<font face='Lucida Console'>(</font>";
recently_seen_paren = false;
++paren_count;
break;
case '>':
recently_seen_include = false;
out << "<font color='#5555FF'>&gt;</font>";
recently_seen_paren = false;
break;
case '<':
out << "<font color='#5555FF'>&lt;</font>";
recently_seen_paren = false;
break;
case '&':
out << "<font color='#5555FF'>&amp;</font>";
recently_seen_paren = false;
break;
case '=':
case '+':
case '-':
case '/':
case '*':
case '!':
case '|':
case '%':
out << "<font color='#5555FF'>" << token << "</font>";
recently_seen_paren = false;
break;
default:
out << token;
recently_seen_paren = false;
break;
} // switch (token[0])
break;
} // switch (type)
t.get_token(type,token);
} // while (type != tok::END_OF_FILE)
out << "\n</pre></body></html>";
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::print");
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_1<stack,tok>::
print_and_number (
std::istream& in,
std::ostream& out,
const std::string& title
) const
{
using namespace std;
ostringstream sout;
print(in,sout,title);
istringstream sin(sout.str());
number(sin,out);
}
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
// private member function definitions
// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
void cpp_pretty_printer_kernel_1<stack,tok>::
number (
std::istream& in,
std::ostream& out
) const
{
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number");
std::string space = "&nbsp;&nbsp;&nbsp;";
std::ios::int_type ch;
unsigned long count = 1;
while ((ch=in.get()) != EOF)
{
if (ch != '\n')
{
out << (char)ch;
}
else
{
out << "\n<font color='555555'>" << count << " </font> " + space;
++count;
if (count == 10)
space = "&nbsp;&nbsp;";
if (count == 100)
space = "&nbsp;";
if (count == 1000)
space = "";
}
}
if (!out)
throw std::ios::failure("error occurred in cpp_pretty_printer_kernel_1::number");
}
// ----------------------------------------------------------------------------------------
template <
typename stack,
typename tok
>
const std::string cpp_pretty_printer_kernel_1<stack,tok>::
htmlify (
const std::string& str
) const
{
std::string::size_type i;
std::string temp;
for (i = 0; i < str.size(); ++i)
{
if (str[i] == '<')
temp += "&lt;";
else if (str[i] == '>')
temp += "&gt;";
else if (str[i] == '&')
temp += "&amp;";
else
temp += str[i];
}
return temp;
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_1_