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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -95,19 +95,54 @@ public:
// default stack size: 300 // default stack size: 300
void SetStackSize(size_t new_stack_size); 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 // the main methods for generating
void Generate(StreamType & o, Pattern & p, Functions<StreamType> & f); 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 // this method is used only if the pattern has cached functions
void Generate(StreamType & o, Pattern & p); void Generate(StreamType & o, Pattern & p);
void Generate(std::vector<StreamType> & o, Pattern & p);
void Generate(std::vector<StreamType*> & o, Pattern & p);
private: 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; StreamType * output_stream;
Pattern * pattern; Pattern * pattern;
Functions<StreamType> * functions; 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 // temporary error messages
std::wstring temp_msg; std::wstring temp_msg;
@ -130,6 +165,7 @@ private:
const StreamType empty_stream; const StreamType empty_stream;
// temporary streams used in [if..] [is...] or [for...] // 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; StreamType stream_temp1, stream_temp2;
// whether last function has put its content in case_sensitive (set FunInfo::case_sensitive) // 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 PrintNormalText(const wchar_t * start, const wchar_t * end);
void TrimWhite(const wchar_t *& start, const wchar_t *& end); void TrimWhite(const wchar_t *& start, const wchar_t *& end);
void SkipWhite(const wchar_t *& str); 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); 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 wchar_t * type, const wchar_t * arg = 0);
void CreateMsg(const std::wstring & type, const std::wstring & arg); void CreateMsg(const std::wstring & type, const std::wstring & arg);
void CreateMsg(const std::wstring & type); void CreateMsg(const std::wstring & type);
@ -217,9 +254,14 @@ private:
void MakeTextIsno(Item & item); void MakeTextIsno(Item & item);
void MakeTextDefine(Item & item); void MakeTextDefine(Item & item);
void MakeTextFilter(Item & item); void MakeTextFilter(Item & item);
void MakeTextEzc(Item & item);
void MakeText(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 }; // class Generator
@ -243,6 +285,7 @@ Generator<StreamType>::Generator() : empty_stream()
skip_new_line = false; skip_new_line = false;
is_generator_working = false; is_generator_working = false;
stack_size = 300; stack_size = 300;
has_skip_stream_index = false;
} }
@ -257,15 +300,20 @@ Generator<StreamType>::Generator(const Generator<StreamType> & n)
template<class StreamType> template<class StreamType>
Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamType> & n) 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; pattern = n.pattern;
functions = n.functions; functions = n.functions;
max_items = n.max_items; max_items = n.max_items;
max_for_items = n.max_for_items; max_for_items = n.max_for_items;
special_chars = n.special_chars; special_chars = n.special_chars;
trim_white = n.trim_white; trim_white = n.trim_white;
skip_new_line = n.skip_new_line; 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 and stack will be auto resized after next call to Generate() method
filter_size = n.filter_size; 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 StreamType>
template<class CharType> template<class CharType>
@ -463,21 +526,31 @@ void Generator<StreamType>::SetStackSize(size_t new_stack_size)
} }
template<class StreamType> 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( is_generator_working )
{ {
if( o ) CreateMsg(L"generator busy");
CreateMsg(*o, L"generator busy");
return; return;
} }
output_stream = o; output_stream = 0;
pattern = p; output_stream_index.clear();
functions = f; 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; break_generating = false;
current_item = 0; current_item = 0;
@ -491,12 +564,16 @@ void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<Stre
filter_index = 0; filter_index = 0;
stack_index = 0; stack_index = 0;
if( output_stream && pattern ) if( pattern )
{ {
try try
{ {
is_generator_working = true; is_generator_working = true;
MakeText( pattern->item_root ); MakeText( pattern->item_root );
if( output_stream_index.size() > 1 )
WriteTmpStreamToStreams();
is_generator_working = false; is_generator_working = false;
} }
catch(...) catch(...)
@ -508,23 +585,77 @@ void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<Stre
} }
template<class StreamType> template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p, Functions<StreamType> & f) 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> template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p) 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> template<class StreamType>
wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c) wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c)
{ {
@ -695,25 +825,28 @@ return start;
template<class StreamType> template<class StreamType>
void Generator<StreamType>::PrintSpecialText(const wchar_t * start, const wchar_t * end) 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 // looking for a first new line character or a special char
// (for new line only if skip_new_line is true) // (for new line only if skip_new_line is true)
while( end2 != end && *end2 != '\\' && (!skip_new_line || *end2 != 10) ) while( end2 != end && *end2 != '\\' && (!skip_new_line || *end2 != 10) )
end2 += 1; end2 += 1;
// printing the first part of the text // printing the first part of the text
if( start != end2 ) if( start != end2 )
output_stream->write(start, end2 - start); output_stream->write(start, end2 - start);
start = end2; start = end2;
// skipping one or more new line characters or special chars // skipping one or more new line characters or special chars
// (new lines only if skip_new_line is true) // (new lines only if skip_new_line is true)
while( start != end && (*start == '\\' || (skip_new_line && *start == 10)) ) while( start != end && (*start == '\\' || (skip_new_line && *start == 10)) )
start = PrintSpecialChar(start, end); start = PrintSpecialChar(start, end);
}
} }
} }
@ -721,31 +854,34 @@ void Generator<StreamType>::PrintSpecialText(const wchar_t * start, const wchar_
template<class StreamType> template<class StreamType>
void Generator<StreamType>::PrintNormalText(const wchar_t * start, const wchar_t * end) 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 // looking for a first new line character
while( end2 != end && *end2 != 10 ) while( end2 != end && *end2 != 10 )
end2 += 1; end2 += 1;
// printing the first part of the text (until the new line) // printing the first part of the text (until the new line)
if( start != end2 ) if( start != end2 )
output_stream->write(start, end2 - start); output_stream->write(start, end2 - start);
start = end2; start = end2;
// skipping one or more new line characters // skipping one or more new line characters
while( start != end && *start == 10 ) while( start != end && *start == 10 )
start += 1; 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); SkipWhite(str);
*str_end = str;
if( str_end )
*str_end = str;
return res; return res;
} }
template<class StreamType> 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); #ifdef EZC_HAS_SPECIAL_STREAM
out.write(temp_msg.c_str(), temp_msg.size()); 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> template<class StreamType>
void Generator<StreamType>::CreateMsg(const wchar_t * type, const wchar_t * arg) 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; return;
is_generating_normal = true; 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; return;
} }
StreamType * old_stream = output_stream; StreamType * old_stream = output_stream;
output_stream = filter_tab[filter_index]; output_stream = filter_tab[filter_index];
ClearStream(*output_stream); 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 MakeText( *item.item_tab[0] ); // should be only one item - item_container
is_generating_filter = true; 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; output_stream = old_stream;
filter_index -= 1; 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> template<class StreamType>
bool Generator<StreamType>::LimitAchieved() 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_def ) MakeTextDefine(item);
else if( item.type == Item::item_for ) MakeTextFor(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_filter ) MakeTextFilter(item);
else if( item.type == Item::item_ezc ) MakeTextEzc(item);
else if( item.type == Item::item_err ) else if( item.type == Item::item_err )
CreateMsg(L"a wrong directive"); 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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_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_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 struct Function

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2007-2012, Tomasz Sowa * Copyright (c) 2007-2013, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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 // user defined directive
void Pattern::ReadDirectiveNormal(const std::wstring & name, Item & item) 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"include" ) ReadDirectiveInclude(item);
else if( name == L"def" ) ReadDirectiveDef(item); else if( name == L"def" ) ReadDirectiveDef(item);
else if( name == L"filter" ) ReadDirectiveFilter(item); else if( name == L"filter" ) ReadDirectiveFilter(item);
else if( name == L"ezc" ) ReadDirectiveEzc(item);
else if( name == L"#" ) ReadDirectiveComment(item); else if( name == L"#" ) ReadDirectiveComment(item);
else else
ReadDirectiveNormal(name, item); ReadDirectiveNormal(name, item);

View File

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