added: possibility to generate output to more than one stream

Generate() methods can take std::vector with pointers to streams
added: 'ezc' keyword -- currently only for selecting streams
       e.g.
       [ezc stream "0" "3"] - after now the output is generated to streams 0 and 3
  


git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@445 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2013-11-07 10:16:10 +00:00
parent 23ce3e83df
commit 9215130b9d
4 changed files with 311 additions and 66 deletions

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2007-2012, Tomasz Sowa
* Copyright (c) 2007-2013, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -95,19 +95,54 @@ public:
// default stack size: 300
void SetStackSize(size_t new_stack_size);
// do not print anything to stream stream_index
// useful when using Generate() method with StreamType tables
// this is a small optimization if we know that a stream with stream_index will not be used later
// set stream_index to -1 to turn off (default)
void SkipStream(int stream_index);
// the main methods for generating
void Generate(StreamType & o, Pattern & p, Functions<StreamType> & f);
void Generate(std::vector<StreamType> & o, Pattern & p, Functions<StreamType> & f);
void Generate(std::vector<StreamType*> & o, Pattern & p, Functions<StreamType> & f);
// this method is used only if the pattern has cached functions
void Generate(StreamType & o, Pattern & p);
void Generate(std::vector<StreamType> & o, Pattern & p);
void Generate(std::vector<StreamType*> & o, Pattern & p);
private:
// current output stream
// if we are printing only to one stream e.g. [put stream "3"]
// then output_stream is pointing directly to that stream
// but if we are printing to more than one stream e.g. [put stream "0" "2" "5"]
// then output_stream is pointing to tmp_stream and at the end
// tmp_stream is copied to the correct streams
// output_stream can be null e.g. [put stream] without arguments
// in such a case we do not print anything
StreamType * output_stream;
Pattern * pattern;
Functions<StreamType> * functions;
// tmp_stream is used when outputting to more than one stream
// (first we output to tmp_stream and then the content is copied
// to the correct streams)
StreamType tmp_stream;
// pointers to the output streams
std::vector<StreamType*> output_stream_tab;
// indices to output_stream_tab
// they are set by [put stream ...] keyword
// at the beginning there is only one index created automatically - "0"
std::vector<size_t> output_stream_index;
// if has_skip_stream_index is true then when reading stream indices from [put stream ...]
// a stream with skip_stream_index index will be ignored
bool has_skip_stream_index;
size_t skip_stream_index;
// temporary error messages
std::wstring temp_msg;
@ -130,6 +165,7 @@ private:
const StreamType empty_stream;
// temporary streams used in [if..] [is...] or [for...]
// or if output_stream is null and an ezc function should be called
StreamType stream_temp1, stream_temp2;
// whether last function has put its content in case_sensitive (set FunInfo::case_sensitive)
@ -188,10 +224,11 @@ private:
void PrintNormalText(const wchar_t * start, const wchar_t * end);
void TrimWhite(const wchar_t *& start, const wchar_t *& end);
void SkipWhite(const wchar_t *& str);
size_t StrToSize(const wchar_t * str, const wchar_t ** str_end);
size_t StrToSize(const wchar_t * str, const wchar_t ** str_end = 0);
bool LookForLastForStatement(size_t & last_for_index);
void CreateMsg(StreamType & out, const wchar_t * type, const wchar_t * arg = 0);
void WriteTmpStreamToStreams();
void CreateMsg(const wchar_t * type, const wchar_t * arg = 0);
void CreateMsg(const std::wstring & type, const std::wstring & arg);
void CreateMsg(const std::wstring & type);
@ -217,9 +254,14 @@ private:
void MakeTextIsno(Item & item);
void MakeTextDefine(Item & item);
void MakeTextFilter(Item & item);
void MakeTextEzc(Item & item);
void MakeText(Item & item);
void Generate(StreamType * o, Pattern * p, Functions<StreamType> * f);
void MakeEzcStream(Item::Function & fun);
void Generate(Pattern * p, Functions<StreamType> * f);
}; // class Generator
@ -243,6 +285,7 @@ Generator<StreamType>::Generator() : empty_stream()
skip_new_line = false;
is_generator_working = false;
stack_size = 300;
has_skip_stream_index = false;
}
@ -257,15 +300,20 @@ Generator<StreamType>::Generator(const Generator<StreamType> & n)
template<class StreamType>
Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamType> & n)
{
output_stream = n.output_stream;
// !! CHECK ME may output_streams should not be copied?
output_stream_tab = n.output_stream_tab;
output_stream_index = n.output_stream_index;
output_tmp_stream = n.output_tmp_stream;
output_stream = n.output_stream;
pattern = n.pattern;
functions = n.functions;
max_items = n.max_items;
max_for_items = n.max_for_items;
special_chars = n.special_chars;
trim_white = n.trim_white;
skip_new_line = n.skip_new_line;
has_skip_stream_index = n.has_skip_stream_index;
// filter and stack will be auto resized after next call to Generate() method
filter_size = n.filter_size;
@ -372,6 +420,21 @@ void Generator<StreamType>::RemoveStackFunData(Stack & s)
}
template<class StreamType>
void Generator<StreamType>::SkipStream(int stream_index)
{
if( stream_index < 0 )
{
has_skip_stream_index = false;
}
else
{
has_skip_stream_index = true;
skip_stream_index = stream_index;
}
}
template<class StreamType>
template<class CharType>
@ -463,21 +526,31 @@ void Generator<StreamType>::SetStackSize(size_t new_stack_size)
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<StreamType> * f)
void Generator<StreamType>::Generate(Pattern * p, Functions<StreamType> * f)
{
if( is_generator_working )
{
if( o )
CreateMsg(*o, L"generator busy");
CreateMsg(L"generator busy");
return;
}
output_stream = o;
pattern = p;
functions = f;
output_stream = 0;
output_stream_index.clear();
ClearStream(tmp_stream);
if( !output_stream_tab.empty() )
{
if( !has_skip_stream_index || skip_stream_index != 0 )
{
output_stream_index.push_back(0);
output_stream = output_stream_tab[0];
}
}
pattern = p;
functions = f;
break_generating = false;
current_item = 0;
@ -491,12 +564,16 @@ void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<Stre
filter_index = 0;
stack_index = 0;
if( output_stream && pattern )
if( pattern )
{
try
{
is_generator_working = true;
MakeText( pattern->item_root );
if( output_stream_index.size() > 1 )
WriteTmpStreamToStreams();
is_generator_working = false;
}
catch(...)
@ -508,23 +585,77 @@ void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<Stre
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
Generate(&o, &p, &f);
output_stream_tab.resize(1);
output_stream_tab[0] = &o;
Generate(&p, &f);
}
template<class StreamType>
void Generator<StreamType>::Generate(std::vector<StreamType> & o, Pattern & p, Functions<StreamType> & f)
{
output_stream_tab.resize(o.size());
for(size_t i=0 ; i<o.size() ; ++i)
output_stream_tab[i] = &o[i];
Generate(&p, &f);
}
template<class StreamType>
void Generator<StreamType>::Generate(std::vector<StreamType*> & o, Pattern & p, Functions<StreamType> & f)
{
output_stream_tab.resize(o.size());
for(size_t i=0 ; i<o.size() ; ++i)
output_stream_tab[i] = o[i];
Generate(&p, &f);
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p)
{
Generate(&o, &p, 0);
output_stream_tab.resize(1);
output_stream_tab[0] = &o;
Generate(&p, 0);
}
template<class StreamType>
void Generator<StreamType>::Generate(std::vector<StreamType> & o, Pattern & p)
{
output_stream_tab.resize(o.size());
for(size_t i=0 ; i<o.size() ; ++i)
output_stream_tab[i] = &o[i];
Generate(&p, 0);
}
template<class StreamType>
void Generator<StreamType>::Generate(std::vector<StreamType*> & o, Pattern & p)
{
output_stream_tab.resize(o.size());
for(size_t i=0 ; i<o.size() ; ++i)
output_stream_tab[i] = o[i];
Generate(&p, 0);
}
@ -637,7 +768,6 @@ bool Generator<StreamType>::Call(Item::Function & item_fun)
template<class StreamType>
wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c)
{
@ -695,25 +825,28 @@ return start;
template<class StreamType>
void Generator<StreamType>::PrintSpecialText(const wchar_t * start, const wchar_t * end)
{
while( start != end )
if( output_stream )
{
const wchar_t * end2 = start;
while( start != end )
{
const wchar_t * end2 = start;
// looking for a first new line character or a special char
// (for new line only if skip_new_line is true)
while( end2 != end && *end2 != '\\' && (!skip_new_line || *end2 != 10) )
end2 += 1;
// looking for a first new line character or a special char
// (for new line only if skip_new_line is true)
while( end2 != end && *end2 != '\\' && (!skip_new_line || *end2 != 10) )
end2 += 1;
// printing the first part of the text
if( start != end2 )
output_stream->write(start, end2 - start);
// printing the first part of the text
if( start != end2 )
output_stream->write(start, end2 - start);
start = end2;
// skipping one or more new line characters or special chars
// (new lines only if skip_new_line is true)
while( start != end && (*start == '\\' || (skip_new_line && *start == 10)) )
start = PrintSpecialChar(start, end);
start = end2;
// skipping one or more new line characters or special chars
// (new lines only if skip_new_line is true)
while( start != end && (*start == '\\' || (skip_new_line && *start == 10)) )
start = PrintSpecialChar(start, end);
}
}
}
@ -721,31 +854,34 @@ void Generator<StreamType>::PrintSpecialText(const wchar_t * start, const wchar_
template<class StreamType>
void Generator<StreamType>::PrintNormalText(const wchar_t * start, const wchar_t * end)
{
if( skip_new_line )
if( output_stream )
{
while( start != end )
if( skip_new_line )
{
const wchar_t * end2 = start;
while( start != end )
{
const wchar_t * end2 = start;
// looking for a first new line character
while( end2 != end && *end2 != 10 )
end2 += 1;
// looking for a first new line character
while( end2 != end && *end2 != 10 )
end2 += 1;
// printing the first part of the text (until the new line)
if( start != end2 )
output_stream->write(start, end2 - start);
// printing the first part of the text (until the new line)
if( start != end2 )
output_stream->write(start, end2 - start);
start = end2;
// skipping one or more new line characters
while( start != end && *start == 10 )
start += 1;
start = end2;
// skipping one or more new line characters
while( start != end && *start == 10 )
start += 1;
}
}
else
{
if( start != end )
output_stream->write(start, end - start);
}
}
else
{
if( start != end )
output_stream->write(start, end-start);
}
}
@ -788,18 +924,35 @@ size_t res = 0;
}
SkipWhite(str);
*str_end = str;
if( str_end )
*str_end = str;
return res;
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & out, const wchar_t * type, const wchar_t * arg)
void Generator<StreamType>::WriteTmpStreamToStreams()
{
pattern->CreateMsg(temp_msg, type, arg);
out.write(temp_msg.c_str(), temp_msg.size());
#ifdef EZC_HAS_SPECIAL_STREAM
const std::wstring & str = tmp_stream.Str();
#else
const std::wstring & str = tmp_stream.str();
#endif
if( !str.empty() )
{
for(size_t s = 0 ; s < output_stream_index.size() ; ++s)
{
size_t i = output_stream_index[s];
if( i < output_stream_tab.size() )
output_stream_tab[i]->write(str.c_str(), str.size());
}
ClearStream(tmp_stream);
}
}
@ -808,7 +961,11 @@ void Generator<StreamType>::CreateMsg(StreamType & out, const wchar_t * type, co
template<class StreamType>
void Generator<StreamType>::CreateMsg(const wchar_t * type, const wchar_t * arg)
{
CreateMsg(*output_stream, type, arg);
if( output_stream )
{
pattern->CreateMsg(temp_msg, type, arg);
output_stream->write(temp_msg.c_str(), temp_msg.size());
}
}
@ -871,7 +1028,16 @@ void Generator<StreamType>::MakeTextNormal(Item & item)
return;
is_generating_normal = true;
Call(item.functions[0], *output_stream, false);
if( output_stream )
{
Call(item.functions[0], *output_stream, false);
}
else
{
Call(item.functions[0], stream_temp1, false);
ClearStream(stream_temp1);
}
}
@ -1240,6 +1406,7 @@ void Generator<StreamType>::MakeTextFilter(Item & item)
return;
}
StreamType * old_stream = output_stream;
output_stream = filter_tab[filter_index];
ClearStream(*output_stream);
@ -1250,13 +1417,80 @@ void Generator<StreamType>::MakeTextFilter(Item & item)
MakeText( *item.item_tab[0] ); // should be only one item - item_container
is_generating_filter = true;
Call(function, item.functions[0].params, *old_stream, false, *output_stream);
if( old_stream )
{
Call(function, item.functions[0].params, *old_stream, false, *output_stream);
}
else
{
Call(function, item.functions[0].params, stream_temp1, true, *output_stream);
ClearStream(stream_temp1);
}
ClearStream(*output_stream);
output_stream = old_stream;
filter_index -= 1;
}
template<class StreamType>
void Generator<StreamType>::MakeEzcStream(Item::Function & fun)
{
if( output_stream_index.size() > 1 )
WriteTmpStreamToStreams();
output_stream_index.clear();
for(size_t i=0 ; i<fun.params.size() ; ++i)
{
size_t index = StrToSize(fun.params[i].c_str());
if( index < output_stream_tab.size() )
{
if( !has_skip_stream_index || skip_stream_index != index )
output_stream_index.push_back(index);
}
// we do not print any information if the index is out of range
// because we do not know to which stream is should be printed
}
if( output_stream_index.size() > 1 )
{
ClearStream(tmp_stream);
output_stream = &tmp_stream;
}
else
if( output_stream_index.size() == 1 )
{
size_t index = output_stream_index[0];
output_stream = output_stream_tab[index];
}
else
{
output_stream = 0;
}
}
template<class StreamType>
void Generator<StreamType>::MakeTextEzc(Item & item)
{
for(size_t i=0 ; i<item.functions.size() ; ++i)
{
if( item.functions[i].name == L"stream" )
MakeEzcStream(item.functions[i]);
else
CreateMsg(L"incorrect argument to [ezc] statement");
// in the future we can use more builtin functions
}
}
template<class StreamType>
bool Generator<StreamType>::LimitAchieved()
{
@ -1310,6 +1544,7 @@ void Generator<StreamType>::MakeText(Item & item)
else if( item.type == Item::item_def ) MakeTextDefine(item);
else if( item.type == Item::item_for ) MakeTextFor(item);
else if( item.type == Item::item_filter ) MakeTextFilter(item);
else if( item.type == Item::item_ezc ) MakeTextEzc(item);
else if( item.type == Item::item_err )
CreateMsg(L"a wrong directive");

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2007-2011, Tomasz Sowa
* Copyright (c) 2007-2013, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -55,7 +55,8 @@ struct Item
{
item_none, item_container, item_text, item_normal, item_is, item_isno,
item_if, item_ifno, item_ifany, item_ifone, item_ifanyno, item_ifoneno, item_ifindex,
item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter
item_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter,
item_ezc
};
struct Function

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2007-2012, Tomasz Sowa
* Copyright (c) 2007-2013, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -837,6 +837,13 @@ void Pattern::ReadDirectiveFilter(Item & item)
}
void Pattern::ReadDirectiveEzc(Item & item)
{
item.type = Item::item_ezc;
ReadFunctions(item);
}
// user defined directive
void Pattern::ReadDirectiveNormal(const std::wstring & name, Item & item)
@ -872,6 +879,7 @@ std::wstring name;
else if( name == L"include" ) ReadDirectiveInclude(item);
else if( name == L"def" ) ReadDirectiveDef(item);
else if( name == L"filter" ) ReadDirectiveFilter(item);
else if( name == L"ezc" ) ReadDirectiveEzc(item);
else if( name == L"#" ) ReadDirectiveComment(item);
else
ReadDirectiveNormal(name, item);

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2007-2012, Tomasz Sowa
* Copyright (c) 2007-2013, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -200,6 +200,7 @@ private:
void ReadDirectiveInclude(Item & item);
void ReadDirectiveDef(Item & item);
void ReadDirectiveFilter(Item & item);
void ReadDirectiveEzc(Item & item);
void ReadDirectiveNormal(const std::wstring & name, Item & item);
void CreateTreeReadItemDirectiveCheckEnding(Item & item);