From 542e50d7576e40a657acb549e7dbc92458bb2e00 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Wed, 26 Jan 2011 12:42:49 +0000 Subject: [PATCH] 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 --- src/functions.h | 8 +- src/funinfo.h | 9 +- src/generator.h | 329 +++++++++++++++++++++++++++++++++++------------- src/item.h | 4 +- src/pattern.cpp | 15 ++- src/pattern.h | 3 +- 6 files changed, 269 insertions(+), 99 deletions(-) diff --git a/src/functions.h b/src/functions.h index 928c247..3733ad1 100755 --- a/src/functions.h +++ b/src/functions.h @@ -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::Function::Function() { type = Functions::variable; user_function = 0; - is_running = false; } diff --git a/src/funinfo.h b/src/funinfo.h index 0f9f231..65f3c57 100755 --- a/src/funinfo.h +++ b/src/funinfo.h @@ -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 & pars, const std::wstring & p) : out(o), params(pars), par(p) + FunInfo(StreamType & o, + std::vector & pars, + const std::wstring & first_par, + const StreamType & i) : out(o), params(pars), par(first_par), in(i) { Clear(); } diff --git a/src/generator.h b/src/generator.h index 3cdf22e..6ba213b 100755 --- a/src/generator.h +++ b/src/generator.h @@ -43,6 +43,8 @@ #include "functions.h" #include #include +#include + 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 & f); @@ -103,6 +112,17 @@ private: bool special_chars; 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 filter_tab; + const StreamType empty_stream; + + + bool is_used; + // an empty string for info objects // when there is no any parameters @@ -119,15 +139,20 @@ private: // a stack for 'for' statements std::vector stack_tab; + void ResizeFilterTab(); + void ClearFilterTab(); + void ClearStream(StreamType & str); + bool Find(const Item::Function & item_fun, typename Functions::Function ** function); void Call(typename Functions::Function * function, FunInfo & info); + void Call(typename Functions::Function * function, std::vector & params, + StreamType & out_stream, const StreamType & in_stream, bool * info_res = 0); + bool Call(Item::Function & function, bool * info_res = 0, typename Functions::Function ** pfun = 0); void Call(typename Functions::Function * function, std::vector & params, bool * info_res = 0); - void CallUserFunction(typename Functions::Function * function, FunInfo & info); - void CallVariable(typename Functions::Function * function, FunInfo & info); - + wchar_t CreateSpecialChar(wchar_t c); const wchar_t * PrintSpecialChar(const wchar_t * start, const wchar_t * end); void PrintSpecialText(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 * f); + }; // class Generator @@ -176,12 +205,94 @@ Generator::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 +Generator::Generator(const Generator & n) +{ + operator=(n); +} + + + +template +Generator & Generator::operator=(const Generator & 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 +Generator::~Generator() +{ + ClearFilterTab(); +} + + +template +void Generator::ResizeFilterTab() +{ + if( filter_tab.size() != filter_size ) + { + if( filter_tab.size() < filter_size ) + { + for(size_t i=filter_tab.size() ; i +void Generator::ClearFilterTab() +{ + for(size_t i=0 ; i +void Generator::ClearStream(StreamType & str) +{ + #ifdef EZC_HAS_SPECIAL_STREAM + str.Clear(); + #else + str.str(L""); + #endif +} template @@ -214,30 +325,64 @@ void Generator::SkipNewLine(bool skip) template -void Generator::Generate(StreamType & o, Pattern & p, Functions & f) +void Generator::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 +void Generator::Generate(StreamType * o, Pattern * p, Functions * 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 +void Generator::Generate(StreamType & o, Pattern & p, Functions & f) +{ + Generate(&o, &p, &f); +} + + + template void Generator::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 -void Generator::CallUserFunction(typename Functions::Function * function, FunInfo & 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 -void Generator::CallVariable(typename Functions::Function * function, FunInfo & info) -{ - info.res = !function->variable.empty(); -} - template @@ -308,52 +430,54 @@ void Generator::Call(typename Functions::Function * func info.iter = stack_tab.back().iter; if( function->type == Functions::function ) - CallUserFunction(function, info); + (function->user_function)(info); else - CallVariable(function, info); + info.res = !function->variable.empty(); } +template +void Generator::Call(typename Functions::Function * function, + std::vector & params, + StreamType & out_stream, const StreamType & in_stream, + bool * info_res) +{ + if( params.empty() ) + { + FunInfo info(out_stream, params, empty, in_stream); + Call(function, info); + + if( info_res ) + *info_res = info.res; + } + else + { + FunInfo 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 bool Generator::Call(Item::Function & item_fun, bool * info_res, typename Functions::Function ** pfun) { typename Functions::Function * fun; -bool called = false; - if( item_fun.params.empty() ) - { - FunInfo 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 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 void Generator::Call(typename Functions::Function * function, std::vector & params, bool * info_res) { - if( params.empty() ) - { - FunInfo info(*output_stream, params, empty); - Call(function, info); - - if( info_res ) - *info_res = info.res; - } - else - { - FunInfo 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 wchar_t Generator::CreateSpecialChar(wchar_t c) { @@ -540,12 +650,20 @@ return res; +template +void Generator::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 void Generator::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::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::MakeTextDefine(Item & item) +template +void Generator::MakeTextFilter(Item & item) +{ + if( item.functions.size() != 1 ) + return; + + typename Functions::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 void Generator::MakeText(Item & item) { @@ -957,6 +1109,7 @@ void Generator::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"); } diff --git a/src/item.h b/src/item.h index e577b3f..18c5777 100755 --- a/src/item.h +++ b/src/item.h @@ -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 diff --git a/src/pattern.cpp b/src/pattern.cpp index 87d1065..bd59b86 100755 --- a/src/pattern.cpp +++ b/src/pattern.cpp @@ -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 ) diff --git a/src/pattern.h b/src/pattern.h index 3f1b16d..1a50414 100755 --- a/src/pattern.h +++ b/src/pattern.h @@ -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);