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:
parent
3c85fa1a75
commit
542e50d757
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
327
src/generator.h
327
src/generator.h
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue