added filters:

a new statement [filter]
 syntax:
 [filter funcion_name]....[end]
 everything which is between [filter] and [end] is processed normally and
 at the end it is passed to the function (function_name)
 FunInfo struct has 'in' input stream now



git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@333 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2011-01-26 12:42:49 +00:00
parent 3c85fa1a75
commit 542e50d757
6 changed files with 269 additions and 99 deletions

View File

@ -59,14 +59,11 @@ public:
struct Function
{
Type type;
Function();
Type type;
UserFunction user_function; // used when type is 'function'
std::wstring variable; // used when type is 'variable'
bool is_running; // true if this function is currently executed
Function();
};
@ -101,7 +98,6 @@ Functions<StreamType>::Function::Function()
{
type = Functions::variable;
user_function = 0;
is_running = false;
}

View File

@ -63,6 +63,10 @@ struct FunInfo
// in such a way the reference points to an empty string
const std::wstring & par;
// an input stream used in [filter] statement
// if there is other statement than [filter] then this is an empty stream
const StreamType & in;
// this is set by Generator
// it indicates the number of a current iteration in the last [for] statement (the first is 0)
// if there was not any [for] before the value is zero
@ -73,7 +77,10 @@ struct FunInfo
bool res;
// arguments: output_stream, table_of_parameters, the_first_parameter
FunInfo(StreamType & o, std::vector<std::wstring> & pars, const std::wstring & p) : out(o), params(pars), par(p)
FunInfo(StreamType & o,
std::vector<std::wstring> & pars,
const std::wstring & first_par,
const StreamType & i) : out(o), params(pars), par(first_par), in(i)
{
Clear();
}

View File

@ -43,6 +43,8 @@
#include "functions.h"
#include <sstream>
#include <fstream>
#include <vector>
namespace Ezc
{
@ -56,6 +58,10 @@ class Generator
public:
Generator();
Generator(const Generator & n);
Generator & operator=(const Generator & n);
~Generator();
void SetMax(int max_items_, int max_for_items_);
@ -80,6 +86,9 @@ public:
// default: false
void SkipNewLine(bool skip);
// default: 20
void SetMaxFilters(size_t new_len);
// the main methods for generating
void Generate(StreamType & o, Pattern & p, Functions<StreamType> & f);
@ -104,6 +113,17 @@ private:
bool trim_white;
bool skip_new_line;
size_t filter_index;
size_t filter_size;
// we have to use a pointers table because standard streams such
// as std::wostringstream are not copyable
std::vector<StreamType*> filter_tab;
const StreamType empty_stream;
bool is_used;
// an empty string for info objects
// when there is no any parameters
const std::wstring empty;
@ -119,14 +139,19 @@ private:
// a stack for 'for' statements
std::vector<StackItem> stack_tab;
void ResizeFilterTab();
void ClearFilterTab();
void ClearStream(StreamType & str);
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, std::vector<std::wstring> & params,
StreamType & out_stream, const StreamType & in_stream, bool * info_res = 0);
bool Call(Item::Function & function, bool * info_res = 0, typename Functions<StreamType>::Function ** pfun = 0);
void Call(typename Functions<StreamType>::Function * function, std::vector<std::wstring> & params, bool * info_res = 0);
void CallUserFunction(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
void CallVariable(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info);
wchar_t CreateSpecialChar(wchar_t c);
const wchar_t * PrintSpecialChar(const wchar_t * start, const wchar_t * end);
@ -136,6 +161,7 @@ private:
void SkipWhite(const wchar_t *& str);
int StrToInt(const wchar_t * str, const wchar_t ** str_end);
void CreateMsg(StreamType & out, 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);
@ -158,8 +184,11 @@ private:
void MakeTextIs(Item & item);
void MakeTextIsno(Item & item);
void MakeTextDefine(Item & item);
void MakeTextFilter(Item & item);
void MakeText(Item & item);
void Generate(StreamType * o, Pattern * p, Functions<StreamType> * f);
}; // class Generator
@ -176,12 +205,94 @@ Generator<StreamType>::Generator()
max_items = 50000;
max_for_items = 5000;
filter_size = 20;
special_chars = false;
trim_white = false;
skip_new_line = false;
is_used = false;
}
template<class StreamType>
Generator<StreamType>::Generator(const Generator<StreamType> & n)
{
operator=(n);
}
template<class StreamType>
Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamType> & n)
{
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;
// don't copy filter tab
filter_tab.clear();
// don't copy 'is_used' flag
is_used = false;
return *this;
}
template<class StreamType>
Generator<StreamType>::~Generator()
{
ClearFilterTab();
}
template<class StreamType>
void Generator<StreamType>::ResizeFilterTab()
{
if( filter_tab.size() != filter_size )
{
if( filter_tab.size() < filter_size )
{
for(size_t i=filter_tab.size() ; i<filter_size ; ++i)
filter_tab.push_back( new StreamType() );
}
else
{
for(size_t i=filter_size ; i<filter_tab.size() ; ++i)
delete filter_tab[i];
filter_tab.resize(filter_size);
}
}
}
template<class StreamType>
void Generator<StreamType>::ClearFilterTab()
{
for(size_t i=0 ; i<filter_tab.size() ; ++i)
delete filter_tab[i];
filter_tab.clear();
}
template<class StreamType>
void Generator<StreamType>::ClearStream(StreamType & str)
{
#ifdef EZC_HAS_SPECIAL_STREAM
str.Clear();
#else
str.str(L"");
#endif
}
template<class StreamType>
@ -214,30 +325,64 @@ void Generator<StreamType>::SkipNewLine(bool skip)
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p, Functions<StreamType> & f)
void Generator<StreamType>::SetMaxFilters(size_t new_len)
{
output_stream = &o;
pattern = &p;
functions = &f;
// the table will be resized when Generate() method is called
filter_size = new_len;
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType * o, Pattern * p, Functions<StreamType> * f)
{
if( is_used )
{
if( o )
CreateMsg(*o, L"generator busy");
return;
}
output_stream = o;
pattern = p;
functions = f;
break_generating = false;
current_item = 0;
stack_tab.clear();
ResizeFilterTab();
filter_index = 0;
MakeText( pattern->item_root );
if( output_stream && pattern )
{
try
{
is_used = true;
MakeText( pattern->item_root );
is_used = false;
}
catch(...)
{
is_used = false;
throw;
}
}
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p, Functions<StreamType> & f)
{
Generate(&o, &p, &f);
}
template<class StreamType>
void Generator<StreamType>::Generate(StreamType & o, Pattern & p)
{
output_stream = &o;
pattern = &p;
functions = 0;
break_generating = false;
current_item = 0;
MakeText( pattern->item_root );
Generate(&o, &p, 0);
}
@ -272,29 +417,6 @@ return true;
}
template<class StreamType>
void Generator<StreamType>::CallUserFunction(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
{
if( function->is_running )
{
// recurrences are not allowed
CreateMsg(L"the function is being executed");
return;
}
function->is_running = true;
(function->user_function)(info);
function->is_running = false;
}
template<class StreamType>
void Generator<StreamType>::CallVariable(typename Functions<StreamType>::Function * function, FunInfo<StreamType> & info)
{
info.res = !function->variable.empty();
}
template<class StreamType>
@ -308,52 +430,54 @@ void Generator<StreamType>::Call(typename Functions<StreamType>::Function * func
info.iter = stack_tab.back().iter;
if( function->type == Functions<StreamType>::function )
CallUserFunction(function, info);
(function->user_function)(info);
else
CallVariable(function, info);
info.res = !function->variable.empty();
}
template<class StreamType>
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function,
std::vector<std::wstring> & params,
StreamType & out_stream, const StreamType & in_stream,
bool * info_res)
{
if( params.empty() )
{
FunInfo<StreamType> info(out_stream, params, empty, in_stream);
Call(function, info);
if( info_res )
*info_res = info.res;
}
else
{
FunInfo<StreamType> info(out_stream, params, params[0], in_stream);
Call(function, info);
if( info_res )
*info_res = info.res;
}
}
// return: true if a function or variable was found and called
template<class StreamType>
bool Generator<StreamType>::Call(Item::Function & item_fun, bool * info_res, typename Functions<StreamType>::Function ** pfun)
{
typename Functions<StreamType>::Function * fun;
bool called = false;
if( item_fun.params.empty() )
{
FunInfo<StreamType> info(*output_stream, item_fun.params, empty);
if( !Find(item_fun, &fun) )
return false;
if( Find(item_fun, &fun) )
{
Call(fun, info);
called = true;
}
Call(fun, item_fun.params, *output_stream, empty_stream, info_res);
if( info_res )
*info_res = info.res;
}
else
{
FunInfo<StreamType> info(*output_stream, item_fun.params, item_fun.params[0]);
if( Find(item_fun, &fun) )
{
Call(fun, info);
called = true;
}
if( info_res )
*info_res = info.res;
}
if( called && pfun )
if( pfun )
*pfun = fun;
return called;
return true;
}
@ -363,27 +487,13 @@ return called;
template<class StreamType>
void Generator<StreamType>::Call(typename Functions<StreamType>::Function * function, std::vector<std::wstring> & params, bool * info_res)
{
if( params.empty() )
{
FunInfo<StreamType> info(*output_stream, params, empty);
Call(function, info);
if( info_res )
*info_res = info.res;
}
else
{
FunInfo<StreamType> info(*output_stream, params, params[0]);
Call(function, info);
if( info_res )
*info_res = info.res;
}
Call(function, params, *output_stream, empty_stream, info_res);
}
template<class StreamType>
wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c)
{
@ -540,12 +650,20 @@ return res;
template<class StreamType>
void Generator<StreamType>::CreateMsg(StreamType & out, const wchar_t * type, const wchar_t * arg)
{
pattern->CreateMsg(temp_msg, type, arg);
out.write(temp_msg.c_str(), temp_msg.size());
}
template<class StreamType>
void Generator<StreamType>::CreateMsg(const wchar_t * type, const wchar_t * arg)
{
pattern->CreateMsg(temp_msg, type, arg);
output_stream->write(temp_msg.c_str(), temp_msg.size());
CreateMsg(*output_stream, type, arg);
}
@ -896,7 +1014,7 @@ void Generator<StreamType>::MakeTextDefine(Item & item)
{
if( !functions )
{
CreateMsg(L"def statement is not available when used without functions set");
CreateMsg(L"[def] statement is not available when used without functions set");
return;
}
@ -930,6 +1048,40 @@ void Generator<StreamType>::MakeTextDefine(Item & item)
template<class StreamType>
void Generator<StreamType>::MakeTextFilter(Item & item)
{
if( item.functions.size() != 1 )
return;
typename Functions<StreamType>::Function * function;
if( !Find(item.functions[0], &function) )
return;
if( filter_index >= filter_tab.size() )
{
CreateMsg(L"Generator exceeded allowed number of filters");
return;
}
StreamType * old_stream = output_stream;
output_stream = filter_tab[filter_index];
ClearStream(*output_stream);
filter_index += 1;
if( !item.item_tab.empty() )
MakeText( *item.item_tab[0] ); // should be only one item - item_container
Call(function, item.functions[0].params, *old_stream, *output_stream);
output_stream = old_stream;
filter_index -= 1;
}
template<class StreamType>
void Generator<StreamType>::MakeText(Item & item)
{
@ -957,6 +1109,7 @@ void Generator<StreamType>::MakeText(Item & 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_filter ) MakeTextFilter(item);
else if( item.type == Item::item_err )
CreateMsg(L"a wrong directive");
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2007-2010, Tomasz Sowa
* Copyright (c) 2007-2011, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -55,7 +55,7 @@ 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_for, item_else, item_end, item_err, item_include, item_comment, item_def, item_filter
};
struct Function

View File

@ -827,6 +827,17 @@ void Pattern::ReadDirectiveDef(Item & item)
}
void Pattern::ReadDirectiveFilter(Item & item)
{
item.type = Item::item_filter;
ReadFunctions(item);
if( item.functions.size() != 1 )
item.type = Item::item_err;
}
// user defined directive
void Pattern::ReadDirectiveNormal(const std::wstring & name, Item & item)
{
@ -860,6 +871,7 @@ std::wstring name;
else if( name == L"for" ) ReadDirectiveFor(item);
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"#" ) ReadDirectiveComment(item);
else
ReadDirectiveNormal(name, item);
@ -1009,7 +1021,8 @@ void Pattern::CreateTree(Item & item)
pitem->type == Item::item_isno )
CreateTreeReadIf(*pitem);
if( pitem->type == Item::item_for )
if( pitem->type == Item::item_for ||
pitem->type == Item::item_filter )
CreateTreeReadFor(*pitem);
if( pitem->type == Item::item_include )

View File

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