changed: in Generator:
now we have a stack item for all statements [if...] [normal_fun] etc. previously was only for [for ...] statements changed: FunInfo<> has a pointer to the current stack item changed: now we have a static number of stack items (default: 300) so you can remember a pointer to a stack item and this pointer is always valid git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@393 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
4fc842ad91
commit
787b5e99b2
|
@ -39,7 +39,6 @@
|
|||
#ifndef headerfile_ezc_funinfo
|
||||
#define headerfile_ezc_funinfo
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
@ -47,10 +46,12 @@
|
|||
namespace Ezc
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
a base class for your own function data class
|
||||
*/
|
||||
struct FunData
|
||||
{
|
||||
|
||||
|
||||
FunData()
|
||||
{
|
||||
}
|
||||
|
@ -61,6 +62,40 @@ struct FunData
|
|||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
a generator's stack item
|
||||
each statement ([if ...] [for ...] [normal_funcion]) have its own stack item
|
||||
iter - is used only in [for...] - it is the current iteration (start from zero)
|
||||
for other statements it is always zero
|
||||
fun_data - by default this is null pointer, you can set it to a pointer
|
||||
to an object derived from FunData
|
||||
(this have sense only in [for...] statement because in other statements
|
||||
this object would be immediately removed)
|
||||
remove - when true it means that object pointing by fun_data should be automatically
|
||||
removed -- (by using delete fun_data)
|
||||
*/
|
||||
struct Stack
|
||||
{
|
||||
size_t iter;
|
||||
FunData * fun_data;
|
||||
bool remove;
|
||||
|
||||
Stack()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
iter = 0;
|
||||
fun_data = 0;
|
||||
remove = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
struct FunInfo
|
||||
{
|
||||
|
@ -101,30 +136,19 @@ struct FunInfo
|
|||
// indicates that this function is from a filter statement [filter ...]
|
||||
bool is_filter;
|
||||
|
||||
// a pointer to FunData struct
|
||||
// !! IMPROVE ME
|
||||
// !! give some info here
|
||||
// can be null
|
||||
FunData * fun_data;
|
||||
// a pointer to a stack's item from generator's stack
|
||||
// it is never null
|
||||
// each function has a new stack item
|
||||
// on this stack you have iter (description below) and fun_data pointer
|
||||
// you can assign to it your own object derived from FunData
|
||||
Stack * stack;
|
||||
|
||||
FunData * last_fun_data;
|
||||
|
||||
bool remove_fun_data;
|
||||
|
||||
|
||||
// this is set by Generator
|
||||
// the same as stack->iter (this is mainly for backward compatibility)
|
||||
// it indicates the number of a current iteration for the [for] statement (the first iteration is 0)
|
||||
// if there was not any [for] before the value is zero
|
||||
// for other statements than [for] this is always zero
|
||||
size_t iter;
|
||||
|
||||
// this is set by Generator
|
||||
// it indicates the number of a previous [for] iteration
|
||||
// if there was not any [for] before the value is zero
|
||||
// for a [for] it returns not the current iterator but a value from a previous [for]
|
||||
size_t last_iter;
|
||||
|
||||
// return value from a user function (default false if not set directly by the user function)
|
||||
// return value from a user's function (default false if not set directly by the function)
|
||||
// for a variable it is set to true if the variable is not empty
|
||||
bool res;
|
||||
|
||||
|
@ -147,12 +171,9 @@ struct FunInfo
|
|||
is_is = false;
|
||||
is_normal = false;
|
||||
is_filter = false;
|
||||
stack = 0;
|
||||
iter = 0;
|
||||
last_iter = 0;
|
||||
case_sensitive = true;
|
||||
remove_fun_data = true;
|
||||
fun_data = 0;
|
||||
last_fun_data = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
239
src/generator.h
239
src/generator.h
|
@ -48,6 +48,9 @@
|
|||
|
||||
namespace Ezc
|
||||
{
|
||||
|
||||
|
||||
|
||||
/*
|
||||
StreamType
|
||||
we use only method write(const wchar_t * str, size_t len) from the stream
|
||||
|
@ -89,6 +92,9 @@ public:
|
|||
// default: 20
|
||||
void SetMaxFilters(size_t new_len);
|
||||
|
||||
// default stack size: 300
|
||||
void SetStackSize(size_t new_stack_size);
|
||||
|
||||
// the main methods for generating
|
||||
void Generate(StreamType & o, Pattern & p, Functions<StreamType> & f);
|
||||
|
||||
|
@ -112,7 +118,10 @@ private:
|
|||
bool special_chars;
|
||||
bool trim_white;
|
||||
bool skip_new_line;
|
||||
|
||||
|
||||
size_t stack_index;
|
||||
size_t stack_size;
|
||||
|
||||
size_t filter_index;
|
||||
size_t filter_size;
|
||||
// we have to use a pointers table because standard streams such
|
||||
|
@ -143,31 +152,16 @@ private:
|
|||
// when there is no any parameters
|
||||
const std::wstring empty;
|
||||
|
||||
// a stack item for [for] statements
|
||||
// currently only one item (iterator)
|
||||
struct StackItem
|
||||
{
|
||||
size_t iter;
|
||||
FunData * fun_data;
|
||||
bool remove;
|
||||
|
||||
StackItem()
|
||||
{
|
||||
iter = 0;
|
||||
fun_data = 0;
|
||||
remove = true;
|
||||
}
|
||||
};
|
||||
|
||||
// a stack for [for] statements
|
||||
std::vector<StackItem> stack_tab;
|
||||
std::vector<Stack> stack_tab;
|
||||
|
||||
|
||||
void ResizeFilterTab();
|
||||
void ResizeStack();
|
||||
void ClearFilterTab();
|
||||
void ClearForStack();
|
||||
void ClearForStack(bool resize_stack = true);
|
||||
void ClearStream(StreamType & str);
|
||||
void RemoveStackFunData(StackItem & sitem);
|
||||
void RemoveStackFunData(Stack & sitem);
|
||||
|
||||
template<class CharType>
|
||||
CharType ToLower(CharType c);
|
||||
|
@ -180,7 +174,6 @@ private:
|
|||
|
||||
bool Find(const Item::Function & item_fun, typename Functions<StreamType>::Function ** function);
|
||||
|
||||
void PrepareInfo(FunInfo<StreamType> & info);
|
||||
void Call(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
|
||||
void Call(typename Functions<StreamType>::Function * function, std::vector<std::wstring> & params,
|
||||
StreamType & out_stream, bool clear_out_stream, const StreamType & in_stream);
|
||||
|
@ -202,6 +195,7 @@ private:
|
|||
void CreateMsg(const std::wstring & type, const std::wstring & arg);
|
||||
void CreateMsg(const std::wstring & type);
|
||||
void CreateUnknownMsg(const std::wstring & fun);
|
||||
bool LimitAchieved();
|
||||
|
||||
void MakeTextIf_go(Item & item, bool result);
|
||||
bool MakeTextIfindexnumber(Item & item, bool & result);
|
||||
|
@ -247,6 +241,7 @@ Generator<StreamType>::Generator()
|
|||
trim_white = false;
|
||||
skip_new_line = false;
|
||||
is_generator_working = false;
|
||||
stack_size = 300;
|
||||
}
|
||||
|
||||
|
||||
|
@ -261,23 +256,22 @@ Generator<StreamType>::Generator(const Generator<StreamType> & n)
|
|||
template<class StreamType>
|
||||
Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamType> & n)
|
||||
{
|
||||
output_stream = n.output_stream;
|
||||
pattern = n.pattern;
|
||||
functions = n.functions;
|
||||
output_stream = n.output_stream;
|
||||
pattern = n.pattern;
|
||||
functions = n.functions;
|
||||
|
||||
max_items = n.max_items;
|
||||
max_for_items = n.max_for_items;
|
||||
filter_size = n.filter_size;
|
||||
special_chars = n.special_chars;
|
||||
trim_white = n.trim_white;
|
||||
skip_new_line = n.skip_new_line;
|
||||
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;
|
||||
|
||||
// filter and stack will be auto resized after next call to Generate() method
|
||||
filter_size = n.filter_size;
|
||||
stack_size = n.stack_size;
|
||||
|
||||
// !! IMROVE ME
|
||||
// does we really need to clear those two stacks?
|
||||
// don't copy filter tab
|
||||
ClearFilterTab();
|
||||
// don't copy [for] stack
|
||||
ClearForStack();
|
||||
// don't copy stack
|
||||
|
||||
// !! CHECK ME
|
||||
// may copying should be denied when generator is working?
|
||||
|
@ -318,6 +312,22 @@ void Generator<StreamType>::ResizeFilterTab()
|
|||
}
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::ResizeStack()
|
||||
{
|
||||
if( stack_tab.size() != stack_size )
|
||||
{
|
||||
if( stack_tab.size() > stack_size )
|
||||
{
|
||||
for(size_t i=stack_size ; i<stack_tab.size() ; ++i)
|
||||
RemoveStackFunData(stack_tab[i]);
|
||||
}
|
||||
|
||||
stack_tab.resize(stack_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::ClearFilterTab()
|
||||
{
|
||||
|
@ -329,12 +339,13 @@ void Generator<StreamType>::ClearFilterTab()
|
|||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::ClearForStack()
|
||||
void Generator<StreamType>::ClearForStack(bool resize_stack)
|
||||
{
|
||||
for(size_t i=0 ; i<stack_tab.size() ; ++i)
|
||||
RemoveStackFunData(stack_tab[i]);
|
||||
|
||||
stack_tab.clear();
|
||||
if( resize_stack )
|
||||
stack_tab.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -350,12 +361,12 @@ void Generator<StreamType>::ClearStream(StreamType & str)
|
|||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::RemoveStackFunData(StackItem & sitem)
|
||||
void Generator<StreamType>::RemoveStackFunData(Stack & s)
|
||||
{
|
||||
if( sitem.fun_data && sitem.remove )
|
||||
if( s.fun_data && s.remove )
|
||||
{
|
||||
delete sitem.fun_data;
|
||||
sitem.fun_data = 0;
|
||||
delete s.fun_data;
|
||||
s.fun_data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -443,6 +454,14 @@ void Generator<StreamType>::SetMaxFilters(size_t new_len)
|
|||
}
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::SetStackSize(size_t new_stack_size)
|
||||
{
|
||||
// the stack will be resized when Generate() method is called
|
||||
stack_size = new_stack_size;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<StreamType> * f)
|
||||
{
|
||||
|
@ -460,9 +479,16 @@ void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<Stre
|
|||
|
||||
break_generating = false;
|
||||
current_item = 0;
|
||||
ClearForStack();
|
||||
|
||||
// in the case that there something has left on the stack
|
||||
// from previous call to Generate()
|
||||
// (an exception could have been thrown)
|
||||
ClearForStack(false);
|
||||
|
||||
ResizeFilterTab();
|
||||
ResizeStack();
|
||||
filter_index = 0;
|
||||
stack_index = 0;
|
||||
|
||||
if( output_stream && pattern )
|
||||
{
|
||||
|
@ -528,8 +554,9 @@ return true;
|
|||
}
|
||||
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::PrepareInfo(FunInfo<StreamType> & info)
|
||||
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
|
||||
{
|
||||
info.Clear();
|
||||
|
||||
|
@ -539,35 +566,8 @@ void Generator<StreamType>::PrepareInfo(FunInfo<StreamType> & info)
|
|||
info.is_normal = is_generating_normal;
|
||||
info.is_filter = is_generating_filter;
|
||||
|
||||
if( info.is_for )
|
||||
{
|
||||
if( !stack_tab.empty() )
|
||||
info.iter = stack_tab.back().iter;
|
||||
|
||||
if( stack_tab.size() >= 2 )
|
||||
info.last_iter = stack_tab[stack_tab.size()-2].iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !stack_tab.empty() )
|
||||
info.last_iter = stack_tab.back().iter;
|
||||
}
|
||||
|
||||
if( !stack_tab.empty() )
|
||||
{
|
||||
info.fun_data = stack_tab.back().fun_data;
|
||||
info.remove_fun_data = stack_tab.back().remove;
|
||||
}
|
||||
|
||||
if( stack_tab.size() >= 2 )
|
||||
info.last_fun_data = stack_tab[stack_tab.size()-2].fun_data;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
|
||||
{
|
||||
PrepareInfo(info);
|
||||
info.stack = &stack_tab[stack_index-1];
|
||||
info.iter = stack_tab[stack_index-1].iter;
|
||||
|
||||
if( function->type == Functions<StreamType>::function )
|
||||
{
|
||||
|
@ -579,22 +579,6 @@ void Generator<StreamType>::Call(typename Functions<StreamType>::Function * func
|
|||
info.res = !function->variable.empty();
|
||||
}
|
||||
|
||||
if( !stack_tab.empty() )
|
||||
{
|
||||
if( stack_tab.back().fun_data != info.fun_data )
|
||||
{
|
||||
RemoveStackFunData(stack_tab.back());
|
||||
stack_tab.back().fun_data = info.fun_data;
|
||||
}
|
||||
|
||||
stack_tab.back().remove = info.remove_fun_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( info.remove_fun_data )
|
||||
delete info.fun_data;
|
||||
}
|
||||
|
||||
last_res = info.res;
|
||||
last_case_sensitive = info.case_sensitive;
|
||||
}
|
||||
|
@ -1087,7 +1071,7 @@ void Generator<StreamType>::MakeTextIsno(Item & item)
|
|||
template<class StreamType>
|
||||
bool Generator<StreamType>::MakeTextIfindexnumber(Item & item, bool & result)
|
||||
{
|
||||
if( item.functions.size() != 1 || stack_tab.empty() )
|
||||
if( item.functions.size() != 1 )
|
||||
return false;
|
||||
|
||||
const wchar_t * number_text = item.functions[0].name.c_str();
|
||||
|
@ -1101,7 +1085,7 @@ bool Generator<StreamType>::MakeTextIfindexnumber(Item & item, bool & result)
|
|||
return false;
|
||||
}
|
||||
|
||||
result = (stack_tab.back().iter == number);
|
||||
result = (stack_tab[stack_index-1].iter == number);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1116,27 +1100,24 @@ void Generator<StreamType>::MakeTextIfindex(Item & item)
|
|||
|
||||
bool result = false;
|
||||
|
||||
if( !stack_tab.empty() )
|
||||
if( item.functions[0].name == L"odd" )
|
||||
{
|
||||
if( item.functions[0].name == L"odd" )
|
||||
{
|
||||
result = (stack_tab.back().iter & 1) == 1;
|
||||
}
|
||||
else
|
||||
if( item.functions[0].name == L"even" )
|
||||
{
|
||||
result = (stack_tab.back().iter & 1) == 0;
|
||||
}
|
||||
else
|
||||
if( item.functions[0].name == L"first" )
|
||||
{
|
||||
result = stack_tab.back().iter == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !MakeTextIfindexnumber(item, result) )
|
||||
return;
|
||||
}
|
||||
result = (stack_tab[stack_index-1].iter & 1) == 1;
|
||||
}
|
||||
else
|
||||
if( item.functions[0].name == L"even" )
|
||||
{
|
||||
result = (stack_tab[stack_index-1].iter & 1) == 0;
|
||||
}
|
||||
else
|
||||
if( item.functions[0].name == L"first" )
|
||||
{
|
||||
result = stack_tab[stack_index-1].iter == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !MakeTextIfindexnumber(item, result) )
|
||||
return;
|
||||
}
|
||||
|
||||
MakeTextIf_go(item, result);
|
||||
|
@ -1147,9 +1128,9 @@ void Generator<StreamType>::MakeTextIfindex(Item & item)
|
|||
template<class StreamType>
|
||||
void Generator<StreamType>::MakeTextForLoop(Item & item, typename Functions<StreamType>::Function * function)
|
||||
{
|
||||
for( ; !break_generating ; stack_tab.back().iter += 1 )
|
||||
for( ; !break_generating ; stack_tab[stack_index-1].iter += 1 )
|
||||
{
|
||||
if( stack_tab.back().iter >= max_for_items )
|
||||
if( stack_tab[stack_index-1].iter >= max_for_items )
|
||||
{
|
||||
CreateMsg(item.functions[0].name.c_str(),
|
||||
L"function exceeded a limit for a [for] statement");
|
||||
|
@ -1181,10 +1162,7 @@ void Generator<StreamType>::MakeTextFor(Item & item)
|
|||
if( !Find(item.functions[0], &function) )
|
||||
return;
|
||||
|
||||
stack_tab.push_back(StackItem());
|
||||
MakeTextForLoop(item, function);
|
||||
RemoveStackFunData(stack_tab.back());
|
||||
stack_tab.erase(--stack_tab.end());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1262,26 +1240,44 @@ void Generator<StreamType>::MakeTextFilter(Item & item)
|
|||
}
|
||||
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::MakeText(Item & item)
|
||||
bool Generator<StreamType>::LimitAchieved()
|
||||
{
|
||||
if( break_generating )
|
||||
return;
|
||||
return true;
|
||||
|
||||
if( ++current_item > max_items )
|
||||
{
|
||||
break_generating = true;
|
||||
CreateMsg(L"Generator exceeded allowed number of elements");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ++stack_index > stack_tab.size() )
|
||||
{
|
||||
break_generating = true;
|
||||
CreateMsg(L"Generator exceeded the stack size");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<class StreamType>
|
||||
void Generator<StreamType>::MakeText(Item & item)
|
||||
{
|
||||
if( LimitAchieved() )
|
||||
return;
|
||||
|
||||
is_generating_for = false;
|
||||
is_generating_if = false;
|
||||
is_generating_is = false;
|
||||
is_generating_normal = false;
|
||||
is_generating_filter = false;
|
||||
|
||||
stack_tab[stack_index-1].Clear();
|
||||
|
||||
if ( item.type == Item::item_text ) MakeItemText(item);
|
||||
else if( item.type == Item::item_container )MakeTextContainer(item);
|
||||
else if( item.type == Item::item_normal ) MakeTextNormal(item);
|
||||
|
@ -1294,11 +1290,14 @@ void Generator<StreamType>::MakeText(Item & item)
|
|||
else if( item.type == Item::item_ifindex ) MakeTextIfindex(item);
|
||||
else if( item.type == Item::item_is ) MakeTextIs(item);
|
||||
else if( item.type == Item::item_isno ) MakeTextIsno(item);
|
||||
else if( item.type == Item::item_for ) MakeTextFor(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_err )
|
||||
CreateMsg(L"a wrong directive");
|
||||
|
||||
RemoveStackFunData(stack_tab[stack_index-1]);
|
||||
stack_index -=1;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue