changed: [is...] statements use only the output string now (when comparing)

previously they used FunInfo::res, now they use FunInfo::out
         and the out string is not put to the main output stream
added:   FunInfo<>::case_sensitive (default true)
         when false then [is] statement is comparing in case insensitive manner
changed: the out stream in [if...] [for] statements
         the output text is ingored now



git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@344 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2011-04-26 17:17:06 +00:00
parent 542e50d757
commit 861269383e
3 changed files with 162 additions and 84 deletions

View File

@ -54,6 +54,11 @@ struct FunInfo
// output stream // output stream
StreamType & out; StreamType & out;
// the out stream is treated in case sensitive
// used only in [is...] statements
// default: true
bool case_sensitive;
// table of parameters // table of parameters
// the table can be empty // the table can be empty
std::vector<std::wstring> & params; std::vector<std::wstring> & params;
@ -89,6 +94,7 @@ struct FunInfo
{ {
res = false; // false by default res = false; // false by default
iter = 0; iter = 0;
case_sensitive = true;
} }
}; };

View File

@ -120,37 +120,54 @@ private:
std::vector<StreamType*> filter_tab; std::vector<StreamType*> filter_tab;
const StreamType empty_stream; const StreamType empty_stream;
// temporary streams used in [if..] [is...] or [for...]
StreamType stream_temp1, stream_temp2;
bool is_used; // whether last function has put its content in case_sensitive (set FunInfo::case_sensitive)
bool last_case_sensitive;
// last result from a user function (FunInfo::res)
bool last_res;
// an empty string for info objects // true if this Generator is working now
bool is_generator_working;
// an empty string for FunInfo objects
// when there is no any parameters // when there is no any parameters
const std::wstring empty; const std::wstring empty;
// a stack item for [for] statements
// a stack item for 'for' statements // currently only one item (iterator)
// currently only one item (iteration)
struct StackItem struct StackItem
{ {
int iter; int iter;
}; };
// a stack for 'for' statements // a stack for [for] statements
std::vector<StackItem> stack_tab; std::vector<StackItem> stack_tab;
void ResizeFilterTab(); void ResizeFilterTab();
void ClearFilterTab(); void ClearFilterTab();
void ClearStream(StreamType & str); void ClearStream(StreamType & str);
template<class CharType>
CharType ToLower(CharType c);
template<class CharType>
bool StrCmpNc(CharType * str1, CharType * str2);
bool AreStreamsEqual(StreamType & str1, StreamType & str2, bool case_sensitive);
bool Find(const Item::Function & item_fun, typename Functions<StreamType>::Function ** function); bool Find(const Item::Function & item_fun, typename Functions<StreamType>::Function ** function);
void Call(typename Functions<StreamType>::Function * function, 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, void Call(typename Functions<StreamType>::Function * function, std::vector<std::wstring> & params,
StreamType & out_stream, const StreamType & in_stream, bool * info_res = 0); StreamType & out_stream, bool clear_out_stream, const StreamType & in_stream);
bool Call(Item::Function & function, bool * info_res = 0, typename Functions<StreamType>::Function ** pfun = 0); bool Call(Item::Function & item_fun, StreamType & out_stream, bool clear_out_stream);
void Call(typename Functions<StreamType>::Function * function, std::vector<std::wstring> & params, bool * info_res = 0); bool Call(Item::Function & function);
wchar_t CreateSpecialChar(wchar_t c); wchar_t CreateSpecialChar(wchar_t c);
@ -181,6 +198,7 @@ private:
void MakeItemText(Item & item); void MakeItemText(Item & item);
void MakeTextContainer(Item & item); void MakeTextContainer(Item & item);
void MakeTextNormal(Item & item); void MakeTextNormal(Item & item);
void MakeTextIs(Item & item, bool equal);
void MakeTextIs(Item & item); void MakeTextIs(Item & item);
void MakeTextIsno(Item & item); void MakeTextIsno(Item & item);
void MakeTextDefine(Item & item); void MakeTextDefine(Item & item);
@ -209,7 +227,7 @@ Generator<StreamType>::Generator()
special_chars = false; special_chars = false;
trim_white = false; trim_white = false;
skip_new_line = false; skip_new_line = false;
is_used = false; is_generator_working = false;
} }
@ -238,8 +256,8 @@ Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamT
// don't copy filter tab // don't copy filter tab
filter_tab.clear(); filter_tab.clear();
// don't copy 'is_used' flag // don't copy 'is_generator_working' flag
is_used = false; is_generator_working = false;
return *this; return *this;
} }
@ -295,6 +313,51 @@ void Generator<StreamType>::ClearStream(StreamType & str)
} }
template<class StreamType>
template<class CharType>
CharType Generator<StreamType>::ToLower(CharType c)
{
if( c>='A' && c<='Z' )
return c - 'A' + 'a';
return c;
}
template<class StreamType>
template<class CharType>
bool Generator<StreamType>::StrCmpNc(CharType * str1, CharType * str2)
{
for( ; ToLower(*str1) == ToLower(*str2) ; ++str1, ++str2)
if( *str1 == 0 )
return true;
return false;
}
template<class StreamType>
bool Generator<StreamType>::AreStreamsEqual(StreamType & str1, StreamType & str2, bool case_sensitive)
{
if( case_sensitive )
{
#ifdef EZC_HAS_SPECIAL_STREAM
return str1.Str() == str2.Str();
#else
return str1.str() == str2.str();
#endif
}
else
{
#ifdef EZC_HAS_SPECIAL_STREAM
return StrCmpNc(str1.CStr(), str2.CStr());
#else
return StrCmpNc(str1.str().c_str(), str2.str().c_str());
#endif
}
}
template<class StreamType> template<class StreamType>
void Generator<StreamType>::SetMax(int max_items_, int max_for_items_) void Generator<StreamType>::SetMax(int max_items_, int max_for_items_)
{ {
@ -335,7 +398,7 @@ void Generator<StreamType>::SetMaxFilters(size_t new_len)
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)
{ {
if( is_used ) if( is_generator_working )
{ {
if( o ) if( o )
CreateMsg(*o, L"generator busy"); CreateMsg(*o, L"generator busy");
@ -357,13 +420,13 @@ void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<Stre
{ {
try try
{ {
is_used = true; is_generator_working = true;
MakeText( pattern->item_root ); MakeText( pattern->item_root );
is_used = false; is_generator_working = false;
} }
catch(...) catch(...)
{ {
is_used = false; is_generator_working = false;
throw; throw;
} }
} }
@ -430,9 +493,18 @@ void Generator<StreamType>::Call(typename Functions<StreamType>::Function * func
info.iter = stack_tab.back().iter; info.iter = stack_tab.back().iter;
if( function->type == Functions<StreamType>::function ) if( function->type == Functions<StreamType>::function )
{
(function->user_function)(info); (function->user_function)(info);
}
else else
{
info.out << function->variable;
info.res = !function->variable.empty(); info.res = !function->variable.empty();
info.case_sensitive = true;
}
last_res = info.res;
last_case_sensitive = info.case_sensitive;
} }
@ -440,54 +512,49 @@ void Generator<StreamType>::Call(typename Functions<StreamType>::Function * func
template<class StreamType> template<class StreamType>
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function, void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function,
std::vector<std::wstring> & params, std::vector<std::wstring> & params,
StreamType & out_stream, const StreamType & in_stream, StreamType & out_stream,
bool * info_res) bool clear_out_stream,
const StreamType & in_stream)
{ {
if( clear_out_stream )
ClearStream(out_stream);
if( params.empty() ) if( params.empty() )
{ {
FunInfo<StreamType> info(out_stream, params, empty, in_stream); FunInfo<StreamType> info(out_stream, params, empty, in_stream);
Call(function, info); Call(function, info);
if( info_res )
*info_res = info.res;
} }
else else
{ {
FunInfo<StreamType> info(out_stream, params, params[0], in_stream); FunInfo<StreamType> info(out_stream, params, params[0], in_stream);
Call(function, info); Call(function, info);
if( info_res )
*info_res = info.res;
} }
} }
// return: true if a function or variable was found and called // return: true if a function or variable was found and called
template<class StreamType> template<class StreamType>
bool Generator<StreamType>::Call(Item::Function & item_fun, bool * info_res, typename Functions<StreamType>::Function ** pfun) bool Generator<StreamType>::Call(Item::Function & item_fun, StreamType & out_stream, bool clear_out_stream)
{ {
typename Functions<StreamType>::Function * fun; typename Functions<StreamType>::Function * fun;
if( !Find(item_fun, &fun) ) if( !Find(item_fun, &fun) )
return false; return false;
Call(fun, item_fun.params, *output_stream, empty_stream, info_res); Call(fun, item_fun.params, out_stream, clear_out_stream, empty_stream);
if( pfun )
*pfun = fun;
return true; return true;
} }
// return: true if a function or variable was found and called
// it calls the function pointed by pfun
template<class StreamType> template<class StreamType>
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function, std::vector<std::wstring> & params, bool * info_res) bool Generator<StreamType>::Call(Item::Function & item_fun)
{ {
Call(function, params, *output_stream, empty_stream, info_res); return Call(item_fun, stream_temp1, true);
} }
@ -725,11 +792,7 @@ void Generator<StreamType>::MakeTextNormal(Item & item)
if( item.functions.size() != 1 ) if( item.functions.size() != 1 )
return; return;
typename Functions<StreamType>::Function * pfun; Call(item.functions[0], *output_stream, false);
bool called = Call(item.functions[0], 0, &pfun);
if( called && pfun->type == Functions<StreamType>::variable )
(*output_stream) << pfun->variable;
} }
@ -755,30 +818,26 @@ void Generator<StreamType>::MakeTextIf_go(Item & item, bool result)
template<class StreamType> template<class StreamType>
void Generator<StreamType>::MakeTextIf(Item & item) void Generator<StreamType>::MakeTextIf(Item & item)
{ {
bool info_res;
if( item.functions.size() != 1 ) if( item.functions.size() != 1 )
return; return;
if( !Call(item.functions[0], &info_res) ) if( !Call(item.functions[0]) )
return; return;
MakeTextIf_go(item, info_res); MakeTextIf_go(item, last_res);
} }
template<class StreamType> template<class StreamType>
void Generator<StreamType>::MakeTextIfno(Item & item) void Generator<StreamType>::MakeTextIfno(Item & item)
{ {
bool info_res;
if( item.functions.size() != 1 ) if( item.functions.size() != 1 )
return; return;
if( !Call(item.functions[0], &info_res) ) if( !Call(item.functions[0]) )
return; return;
MakeTextIf_go(item, !info_res); MakeTextIf_go(item, !last_res);
} }
@ -787,14 +846,13 @@ void Generator<StreamType>::MakeTextIfany(Item & item)
{ {
std::vector<typename Item::Function>::iterator d = item.functions.begin(); std::vector<typename Item::Function>::iterator d = item.functions.begin();
unsigned how_many_true = 0; unsigned how_many_true = 0;
bool info_res;
for( ; d != item.functions.end() ; ++d ) for( ; d != item.functions.end() ; ++d )
{ {
if( !Call(*d, &info_res) ) if( !Call(*d) )
return; return;
if( info_res ) if( last_res )
++how_many_true; ++how_many_true;
} }
@ -807,15 +865,16 @@ void Generator<StreamType>::MakeTextIfone(Item & item)
{ {
std::vector<typename Item::Function>::iterator d = item.functions.begin(); std::vector<typename Item::Function>::iterator d = item.functions.begin();
unsigned how_many_true = 0; unsigned how_many_true = 0;
bool info_res;
for( ; d != item.functions.end() ; ++d ) for( ; d != item.functions.end() ; ++d )
{ {
if( Call(*d, &info_res) && info_res ) if( Call(*d) )
{ {
// there is no sense to go through all functions if( last_res )
++how_many_true; {
break; ++how_many_true;
break; // there is no sense to go through all functions
}
} }
} }
@ -828,14 +887,13 @@ void Generator<StreamType>::MakeTextIfanyno(Item & item)
{ {
std::vector<typename Item::Function>::iterator d = item.functions.begin(); std::vector<typename Item::Function>::iterator d = item.functions.begin();
unsigned how_many_true = 0; unsigned how_many_true = 0;
bool info_res;
for( ; d != item.functions.end() ; ++d ) for( ; d != item.functions.end() ; ++d )
{ {
if( !Call(*d, &info_res) ) if( !Call(*d) )
return; return;
if( info_res ) if( last_res )
++how_many_true; ++how_many_true;
} }
@ -848,12 +906,17 @@ void Generator<StreamType>::MakeTextIfoneno(Item & item)
{ {
std::vector<typename Item::Function>::iterator d = item.functions.begin(); std::vector<typename Item::Function>::iterator d = item.functions.begin();
unsigned how_many_false = 0; unsigned how_many_false = 0;
bool info_res;
for( ; d != item.functions.end() ; ++d ) for( ; d != item.functions.end() ; ++d )
{ {
if( Call(*d, &info_res) && !info_res ) if( Call(*d) )
++how_many_false; {
if( !last_res )
{
++how_many_false;
break;
}
}
} }
MakeTextIf_go(item, how_many_false > 0); MakeTextIf_go(item, how_many_false > 0);
@ -862,38 +925,49 @@ void Generator<StreamType>::MakeTextIfoneno(Item & item)
template<class StreamType> template<class StreamType>
void Generator<StreamType>::MakeTextIs(Item & item) void Generator<StreamType>::MakeTextIs(Item & item, bool equal)
{ {
bool info_res1, info_res2;
if( item.functions.size() != 2 ) if( item.functions.size() != 2 )
return; return;
if( !Call(item.functions[0], &info_res1) ) // if one of these two functions has set case_sensitive to false
// then we compare in case insensitive mode
bool case_sensitive = true;
if( !Call(item.functions[0], stream_temp1, true) )
return; return;
if( !Call(item.functions[1], &info_res2) ) if( !last_case_sensitive )
case_sensitive = false;
if( !Call(item.functions[1], stream_temp2, true) )
return; return;
if( !last_case_sensitive )
case_sensitive = false;
MakeTextIf_go(item, info_res1 == info_res2); bool res = AreStreamsEqual(stream_temp1, stream_temp2, case_sensitive);
if( !equal )
res = !res;
MakeTextIf_go(item, res);
} }
template<class StreamType>
void Generator<StreamType>::MakeTextIs(Item & item)
{
MakeTextIs(item, true);
}
template<class StreamType> template<class StreamType>
void Generator<StreamType>::MakeTextIsno(Item & item) void Generator<StreamType>::MakeTextIsno(Item & item)
{ {
bool info_res1, info_res2; MakeTextIs(item, false);
if( item.functions.size() != 2 )
return;
if( !Call(item.functions[0], &info_res1) )
return;
if( !Call(item.functions[1], &info_res2) )
return;
MakeTextIf_go(item, info_res1 != info_res2);
} }
@ -965,8 +1039,6 @@ void Generator<StreamType>::MakeTextIfindex(Item & item)
template<class StreamType> template<class StreamType>
void Generator<StreamType>::MakeTextForLoop(Item & item, typename Functions<StreamType>::Function * function) void Generator<StreamType>::MakeTextForLoop(Item & item, typename Functions<StreamType>::Function * function)
{ {
bool info_res;
for( ; !break_generating ; stack_tab.back().iter += 1 ) for( ; !break_generating ; stack_tab.back().iter += 1 )
{ {
if( stack_tab.back().iter >= max_for_items ) if( stack_tab.back().iter >= max_for_items )
@ -976,9 +1048,9 @@ bool info_res;
break; break;
} }
Call(function, item.functions[0].params, &info_res); Call(function, item.functions[0].params, stream_temp1, true, empty_stream);
if( !info_res ) if( !last_res )
break; break;
if( !item.item_tab.empty() ) if( !item.item_tab.empty() )
@ -1074,7 +1146,7 @@ void Generator<StreamType>::MakeTextFilter(Item & item)
if( !item.item_tab.empty() ) if( !item.item_tab.empty() )
MakeText( *item.item_tab[0] ); // should be only one item - item_container MakeText( *item.item_tab[0] ); // should be only one item - item_container
Call(function, item.functions[0].params, *old_stream, *output_stream); Call(function, item.functions[0].params, *old_stream, false, *output_stream);
output_stream = old_stream; output_stream = old_stream;
filter_index -= 1; filter_index -= 1;

View File

@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2007-2010, Tomasz Sowa * Copyright (c) 2007-2011, 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