added: an optional string parameter to normal statement e.g. [function "parameter"]

parameters to "for" statement  [for function "parameter"]
changed: in Info struct there is a "par" std::string reference now
changed: Info::result to Info::res
removed: Info::is


git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@295 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2010-05-30 21:07:15 +00:00
parent f65178dd0e
commit b89c6daa7d
4 changed files with 231 additions and 111 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2007, Tomasz Sowa Copyright (c) 2007-2010, 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

View File

@ -1,3 +1,3 @@
# DO NOT DELETE # DO NOT DELETE
edanticezc.o: ezc.h /home/tomek/roboczy/winix/core/log.h ezc.o: ezc.h

View File

@ -523,10 +523,18 @@ void Pattern::ReadDirectiveFor(Item & item)
Item::Directive directive = ReadDirective(); Item::Directive directive = ReadDirective();
if( !directive.name.empty() ) if( !directive.name.empty() )
{
item.directives.push_back(directive); item.directives.push_back(directive);
else
item.type = Item::item_err;
Item::Directive parameter = ReadString();
if( !parameter.name.empty() )
item.directives.push_back(parameter);
}
else
{
item.type = Item::item_err;
}
} }
@ -571,6 +579,20 @@ void Pattern::ReadDirectiveDef(Item & item)
} }
void Pattern::ReadDirectiveNormal(Item::Directive & directive, Item & item)
{
// user defined directive
item.directives.push_back(directive);
item.type = Item::item_normal;
// an optional parameter
Item::Directive parameter = ReadString();
if( !parameter.name.empty() )
item.directives.push_back(parameter);
}
void Pattern::CreateTreeReadItemDirective(Item & item) void Pattern::CreateTreeReadItemDirective(Item & item)
{ {
@ -614,11 +636,7 @@ void Pattern::CreateTreeReadItemDirective(Item & item)
if( directive.name == "#" ) if( directive.name == "#" )
ReadDirectiveComment(item); ReadDirectiveComment(item);
else else
{ ReadDirectiveNormal(directive, item);
// user defined
item.directives.push_back(directive);
item.type = Item::item_normal;
}
CreateTreeReadItemDirectiveCheckEnding(item); CreateTreeReadItemDirectiveCheckEnding(item);
} }
@ -865,6 +883,9 @@ Pattern::Item::~Item()
} }
/* /*
* *
* Info * Info
@ -874,14 +895,12 @@ Pattern::Item::~Item()
void Info::Clear() void Info::Clear()
{ {
// default settings indicate 'false' res = false; // false by default
result = false; iter = 0;
is = 0;
iter = 0;
} }
Info::Info(std::ostringstream & o) : out(o) Info::Info(std::ostringstream & o, const std::string & p) : out(o), par(p)
{ {
Clear(); Clear();
} }
@ -889,6 +908,7 @@ Info::Info(std::ostringstream & o) : out(o)
/* /*
* *
* Functions * Functions
@ -967,12 +987,72 @@ void Functions::Clear()
*/ */
Generator::Generator()
{
output_stream = 0;
pattern = 0;
functions = 0;
max_items = 50000;
max_for_items = 5000;
}
Generator::Generator(std::ostringstream & o, Pattern & p, Functions & f)
{
output_stream = &o;
pattern = &p;
functions = &f;
max_items = 50000;
max_for_items = 5000;
}
void Generator::SetOutStream(std::ostringstream & o)
{
output_stream = &o;
}
void Generator::SetPattern(Pattern & p)
{
pattern = &p;
}
void Generator::SetFunctions(Functions & f)
{
functions = &f;
}
void Generator::SetMax(int max_items_, int max_for_items_)
{
max_items = max_items_;
max_for_items = max_for_items_;
}
void Generator::Generate()
{
if( !output_stream || !pattern || !functions )
return;
current_item = 0;
MakeText( pattern->item_root );
}
bool Generator::Find(const std::string & key, Functions::Function ** function) bool Generator::Find(const std::string & key, Functions::Function ** function)
{ {
if( !functions.Find(key, function) ) if( !functions->Find(key, function) )
{ {
CreateMsg(output_stream, "can't find", key.c_str() ); CreateMsg(*output_stream, "can't find", key.c_str() );
return false; return false;
} }
@ -986,7 +1066,7 @@ void Generator::CallUserFunction(Functions::Function * function, Info & info)
if( function->is_running ) if( function->is_running )
{ {
// recurrences are not allowed // recurrences are not allowed
CreateMsg(output_stream, "the function is currently running" ); CreateMsg(*output_stream, "the function is being executed" );
return; return;
} }
@ -996,21 +1076,18 @@ void Generator::CallUserFunction(Functions::Function * function, Info & info)
} }
void Generator::CallVariable(Functions::Function * function, Info & info) void Generator::CallVariable(Functions::Function * function, Info & info)
{ {
if( info.is || function->is_for ) info.res = !function->variable.empty();
return;
info.out << function->variable;
} }
void Generator::Call(Functions::Function * function, Info & info, const std::string * is) void Generator::Call(Functions::Function * function, Info & info)
{ {
info.Clear(); info.Clear();
info.iter = function->iter; info.iter = function->iter;
info.is = is;
if( function->type == Functions::function ) if( function->type == Functions::function )
CallUserFunction(function, info); CallUserFunction(function, info);
@ -1020,13 +1097,13 @@ void Generator::Call(Functions::Function * function, Info & info, const std::str
// return: true if a function or variable was found and called // return: true if a function or variable was found and called
bool Generator::Call(const std::string & name, Info & info, Functions::Function ** pfun, const std::string * is) bool Generator::Call(const std::string & name, Info & info, Functions::Function ** pfun)
{ {
Functions::Function * function; Functions::Function * function;
if( Find(name, &function) ) if( Find(name, &function) )
{ {
Call(function, info, is); Call(function, info);
if( pfun ) if( pfun )
*pfun = function; *pfun = function;
@ -1034,24 +1111,12 @@ bool Generator::Call(const std::string & name, Info & info, Functions::Function
return true; return true;
} }
return false; return false;
} }
Generator::Generator(std::ostringstream & o, Pattern & p, Functions & f) : output_stream(o), pattern(p), functions(f), info1(o), info2(o)
{
}
void Generator::Generate()
{
loop = 0;
MakeText( pattern.item_root );
}
@ -1059,26 +1124,37 @@ void Generator::MakeTextContainer(Pattern::Item & item)
{ {
std::vector<Pattern::Item*>::iterator i = item.item_table.begin(); std::vector<Pattern::Item*>::iterator i = item.item_table.begin();
for( ; i != item.item_table.end() ; ++i ) for( ; i != item.item_table.end() && current_item != -1 ; ++i )
{
MakeText(**i); MakeText(**i);
if( loop < 0 )
break;
}
} }
void Generator::MakeTextNormal(Pattern::Item & item) void Generator::MakeTextNormal(Pattern::Item & item)
{ {
if( item.directives.size() != 1 ) if( item.directives.empty() )
return; return;
Call(item.directives[0].name, info1); Functions::Function * pfun;
bool called;
if( item.directives.size() == 2 )
{
Info info(*output_stream, item.directives[1].name);
called = Call(item.directives[0].name, info, &pfun);
}
else
{
Info info(*output_stream, empty);
called = Call(item.directives[0].name, info, &pfun);
}
if( called && pfun->type == Functions::variable )
*output_stream << pfun->variable;
} }
void Generator::MakeTextIf_go(Pattern::Item & item, bool result) void Generator::MakeTextIf_go(Pattern::Item & item, bool result)
{ {
if( result ) if( result )
@ -1102,11 +1178,12 @@ void Generator::MakeTextIfany(Pattern::Item & item)
for( ; d != item.directives.end() ; ++d ) for( ; d != item.directives.end() ; ++d )
{ {
if( !Call(d->name, info1) ) Info info(*output_stream, empty);
// maybe it should only be treated as a false? (when there is no such a function/variable)
if( !Call(d->name, info) )
return; return;
if( info1.result ) if( info.res )
++how_many_true; ++how_many_true;
} }
@ -1121,7 +1198,9 @@ void Generator::MakeTextIfno(Pattern::Item & item)
for( ; d != item.directives.end() ; ++d ) for( ; d != item.directives.end() ; ++d )
{ {
if( Call(d->name, info1) && info1.result ) Info info(*output_stream, empty);
if( Call(d->name, info) && info.res )
{ {
// there is no sense to go through all functions // there is no sense to go through all functions
++how_many_true; ++how_many_true;
@ -1141,7 +1220,9 @@ void Generator::MakeTextIfone(Pattern::Item & item)
for( ; d != item.directives.end() ; ++d ) for( ; d != item.directives.end() ; ++d )
{ {
if( Call(d->name, info1) && info1.result ) Info info(*output_stream, empty);
if( Call(d->name, info) && info.res )
{ {
// there is no sense to go through all functions // there is no sense to go through all functions
++how_many_true; ++how_many_true;
@ -1163,8 +1244,10 @@ Functions::Function * function;
if( function->type == Functions::function ) if( function->type == Functions::function )
{ {
Call(function, info1, &text); Info info(*output_stream, text);
res = info1.result;
Call(function, info);
res = info.res;
} }
else else
{ {
@ -1190,21 +1273,28 @@ Functions::Function * function1, * function2;
if( function1->type == Functions::function && function2->type == Functions::function ) if( function1->type == Functions::function && function2->type == Functions::function )
{ {
Info info1(*output_stream, empty);
Info info2(*output_stream, empty);
Call(function1, info1); Call(function1, info1);
Call(function2, info2); Call(function2, info2);
res = (info1.result == info2.result); res = (info1.res == info2.res);
} }
else else
if( function1->type == Functions::function ) if( function1->type == Functions::function )
{ {
Call(function1, info1, &fun_name2); // only the former is a function Info info(*output_stream, fun_name2);
res = info1.result;
Call(function1, info); // only the former is a function
res = info.res;
} }
else else
if( function2->type == Functions::function ) if( function2->type == Functions::function )
{ {
Call(function2, info2, &fun_name1); // only the latter is a function Info info(*output_stream, fun_name1);
res = info2.result;
Call(function2, info); // only the latter is a function
res = info.res;
} }
else else
res = (function1->variable == function2->variable); // both are variables res = (function1->variable == function2->variable); // both are variables
@ -1268,14 +1358,11 @@ bool Generator::MakeTextIfindexnumber(Pattern::Item & item, Functions::Function
if( *last_char == '\0' ) if( *last_char == '\0' )
{ {
if( function->iter == number ) result = (function->iter == number);
result = true;
// we don't have to set result as false (false is default)
} }
else else
{ {
CreateMsg(output_stream, "if-index: syntax error"); CreateMsg(*output_stream, "if-index: syntax error");
return false; return false;
} }
@ -1328,11 +1415,43 @@ void Generator::MakeTextIfindex(Pattern::Item & item)
void Generator::MakeTextForLoop(Pattern::Item & item, Functions::Function * function)
{
for( ; current_item != -1 ; ++function->iter )
{
if( function->iter >= max_for_items )
{
CreateMsg(*output_stream, item.directives[0].name.c_str(), "function exceeded a limit for a [for] statement");
break;
}
if( item.directives.size() == 2 )
{
Info info(*output_stream, item.directives[1].name);
Call(function, info);
if( !info.res )
break;
}
else
{
Info info(*output_stream, empty);
Call(function, info);
if( !info.res )
break;
}
if( !item.item_table.empty() )
MakeText( *item.item_table[0] );
}
}
void Generator::MakeTextFor(Pattern::Item & item) void Generator::MakeTextFor(Pattern::Item & item)
{ {
const int max_loop = 5000; if( item.directives.empty() )
if( item.directives.size() != 1 )
return; return;
Functions::Function * function; Functions::Function * function;
@ -1342,26 +1461,14 @@ void Generator::MakeTextFor(Pattern::Item & item)
if( function->is_for ) if( function->is_for )
{ {
CreateMsg(output_stream, item.directives[0].name.c_str(), "this function is already used in a [for] statement"); CreateMsg(*output_stream, item.directives[0].name.c_str(), "this function is already used in a [for] statement");
return; return;
} }
for( function->is_for = true, function->iter=0 ; loop != -1 ; ++function->iter )
{
if( function->iter >= max_loop )
{
CreateMsg(output_stream, item.directives[0].name.c_str(), "function exceeded a limit for a [for] statement");
break;
}
Call(function, info1);
if( !info1.result ) function->is_for = true;
break; function->iter = 0;
if( item.item_table.size() > 0 ) MakeTextForLoop(item, function);
MakeText( *item.item_table[0] );
}
function->is_for = false; function->is_for = false;
function->iter = 0; function->iter = 0;
@ -1376,7 +1483,7 @@ void Generator::MakeTextDefine(Pattern::Item & item)
if( item.directives[1].is_text ) if( item.directives[1].is_text )
{ {
functions.Insert(item.directives[0].name, item.directives[1].name); functions->Insert(item.directives[0].name, item.directives[1].name);
} }
else else
{ {
@ -1385,9 +1492,9 @@ void Generator::MakeTextDefine(Pattern::Item & item)
if( Find(item.directives[1].name, &function) ) if( Find(item.directives[1].name, &function) )
{ {
if( function->type == Functions::function ) if( function->type == Functions::function )
functions.Insert(item.directives[0].name, function->user_function); functions->Insert(item.directives[0].name, function->user_function);
else else
functions.Insert(item.directives[0].name, function->variable); functions->Insert(item.directives[0].name, function->variable);
} }
} }
} }
@ -1397,22 +1504,20 @@ void Generator::MakeTextDefine(Pattern::Item & item)
void Generator::MakeText(Pattern::Item & item) void Generator::MakeText(Pattern::Item & item)
{ {
const int max_loop = 50000; if( current_item == -1 )
if( loop == -1 )
return; return;
if( ++loop > max_loop ) if( ++current_item > max_items )
{ {
loop = -1; current_item = -1;
CreateMsg(output_stream, "Generator exceeded allowed number of elements"); CreateMsg(*output_stream, "Generator exceeded allowed number of elements");
return; return;
} }
switch( item.type ) switch( item.type )
{ {
case Pattern::Item::item_text: case Pattern::Item::item_text:
output_stream << item.text; *output_stream << item.text;
break; break;
case Pattern::Item::item_container: case Pattern::Item::item_container:
MakeTextContainer(item); MakeTextContainer(item);
@ -1445,7 +1550,7 @@ void Generator::MakeText(Pattern::Item & item)
MakeTextDefine(item); MakeTextDefine(item);
break; break;
case Pattern::Item::item_err: case Pattern::Item::item_err:
CreateMsg(output_stream, "a wrong directive"); CreateMsg(*output_stream, "a wrong directive");
break; break;
default: default:
break; break;

View File

@ -164,6 +164,7 @@ private:
void ReadDirectiveComment(Item & item); void ReadDirectiveComment(Item & item);
void ReadDirectiveInclude(Item & item); void ReadDirectiveInclude(Item & item);
void ReadDirectiveDef(Item & item); void ReadDirectiveDef(Item & item);
void ReadDirectiveNormal(Item::Directive & directive, Item & item);
void CreateTreeReadItemDirective(Item & item); void CreateTreeReadItemDirective(Item & item);
@ -185,22 +186,25 @@ private:
struct Info struct Info
{ {
// this variables you can set in your function // output stream
std::ostringstream & out; std::ostringstream & out;
//std::string out_string;
bool result;
// in a [is function "text"] statement this is the pointer to "text" object // an optional string parameter in a normal statement [user_function "parameter"]
// otherwise this is null pointer // or in "is" statement [is user_function "parameter"]
const std::string * is; // or in "for" statement [for user_function "parameter"]
const std::string & par;
// this is set by Generator // this is set by Generator
// normally is 0 // normally is 0
// in a [for] statement it indicates the number of the current iteration (the first is 0) // in a [for] statement it indicates the number of the current iteration (the first is 0)
int iter; int iter;
// return value from a user function (default false if not set directly by the user function)
// for a variable it is set to true if the variable is not empty
bool res;
Info(std::ostringstream & o); // arguments: output_stream, string_parameter
Info(std::ostringstream & o, const std::string & p);
void Clear(); void Clear();
}; };
@ -250,26 +254,36 @@ private:
class Generator class Generator
{ {
public: public:
Generator(std::ostringstream &, Pattern & data, Functions & functions); Generator();
Generator(std::ostringstream & o, Pattern & p, Functions & f);
void SetOutStream(std::ostringstream & o);
void SetPattern(Pattern & p);
void SetFunctions(Functions & f);
void SetMax(int max_items_, int max_for_items_);
void Generate(); void Generate();
private: private:
std::ostringstream & output_stream; std::ostringstream * output_stream;
Pattern & pattern; Pattern * pattern;
Functions & functions; Functions * functions;
Info info1, info2;
int loop;
int current_item;
int max_items;
int max_for_items;
// an empty string for info objects
const std::string empty;
bool Find(const std::string & key, Functions::Function ** function); bool Find(const std::string & key, Functions::Function ** function);
void Call(Functions::Function * function, Info & info, const std::string * is = 0); void Call(Functions::Function * function, Info & info);
bool Call(const std::string & name, Info & info, Functions::Function ** pfun = 0, const std::string * is = 0); bool Call(const std::string & name, Info & info, Functions::Function ** pfun = 0);
void CallUserFunction(Functions::Function * function, Info & info); void CallUserFunction(Functions::Function * function, Info & info);
void CallVariable(Functions::Function * function, Info & info); void CallVariable(Functions::Function * function, Info & info);
@ -280,6 +294,7 @@ private:
void MakeTextIfno(Pattern::Item & item); void MakeTextIfno(Pattern::Item & item);
void MakeTextIfone(Pattern::Item & item); void MakeTextIfone(Pattern::Item & item);
void MakeTextIfindex(Pattern::Item & item); void MakeTextIfindex(Pattern::Item & item);
void MakeTextForLoop(Pattern::Item & item, Functions::Function * function);
void MakeTextFor(Pattern::Item & item); void MakeTextFor(Pattern::Item & item);
void MakeTextContainer(Pattern::Item & item); void MakeTextContainer(Pattern::Item & item);
void MakeTextNormal(Pattern::Item & item); void MakeTextNormal(Pattern::Item & item);