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:
Tomasz Sowa 2012-02-27 17:39:46 +00:00
parent 4fc842ad91
commit 787b5e99b2
2 changed files with 166 additions and 146 deletions

View File

@ -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;
}
};

View File

@ -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;
}