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:
parent
f65178dd0e
commit
b89c6daa7d
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2007, Tomasz Sowa
|
||||
Copyright (c) 2007-2010, Tomasz Sowa
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# DO NOT DELETE
|
||||
|
||||
edanticezc.o: ezc.h /home/tomek/roboczy/winix/core/log.h
|
||||
ezc.o: ezc.h
|
||||
|
|
287
src/ezc.cpp
287
src/ezc.cpp
|
@ -523,10 +523,18 @@ void Pattern::ReadDirectiveFor(Item & item)
|
|||
Item::Directive directive = ReadDirective();
|
||||
|
||||
if( !directive.name.empty() )
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -614,11 +636,7 @@ void Pattern::CreateTreeReadItemDirective(Item & item)
|
|||
if( directive.name == "#" )
|
||||
ReadDirectiveComment(item);
|
||||
else
|
||||
{
|
||||
// user defined
|
||||
item.directives.push_back(directive);
|
||||
item.type = Item::item_normal;
|
||||
}
|
||||
ReadDirectiveNormal(directive, item);
|
||||
|
||||
CreateTreeReadItemDirectiveCheckEnding(item);
|
||||
}
|
||||
|
@ -865,6 +883,9 @@ Pattern::Item::~Item()
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Info
|
||||
|
@ -874,14 +895,12 @@ Pattern::Item::~Item()
|
|||
|
||||
void Info::Clear()
|
||||
{
|
||||
// default settings indicate 'false'
|
||||
result = false;
|
||||
is = 0;
|
||||
iter = 0;
|
||||
res = false; // false by default
|
||||
iter = 0;
|
||||
}
|
||||
|
||||
|
||||
Info::Info(std::ostringstream & o) : out(o)
|
||||
Info::Info(std::ostringstream & o, const std::string & p) : out(o), par(p)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
@ -889,6 +908,7 @@ Info::Info(std::ostringstream & o) : out(o)
|
|||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -986,7 +1066,7 @@ void Generator::CallUserFunction(Functions::Function * function, Info & info)
|
|||
if( function->is_running )
|
||||
{
|
||||
// recurrences are not allowed
|
||||
CreateMsg(output_stream, "the function is currently running" );
|
||||
CreateMsg(*output_stream, "the function is being executed" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -996,21 +1076,18 @@ void Generator::CallUserFunction(Functions::Function * function, Info & info)
|
|||
}
|
||||
|
||||
|
||||
|
||||
void Generator::CallVariable(Functions::Function * function, Info & info)
|
||||
{
|
||||
if( info.is || function->is_for )
|
||||
return;
|
||||
|
||||
info.out << function->variable;
|
||||
info.res = !function->variable.empty();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Generator::Call(Functions::Function * function, Info & info, const std::string * is)
|
||||
void Generator::Call(Functions::Function * function, Info & info)
|
||||
{
|
||||
info.Clear();
|
||||
info.iter = function->iter;
|
||||
info.is = is;
|
||||
|
||||
if( function->type == Functions::function )
|
||||
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
|
||||
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) )
|
||||
{
|
||||
Call(function, info, is);
|
||||
Call(function, info);
|
||||
|
||||
if( pfun )
|
||||
*pfun = function;
|
||||
|
@ -1034,24 +1111,12 @@ bool Generator::Call(const std::string & name, Info & info, Functions::Function
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
for( ; i != item.item_table.end() ; ++i )
|
||||
{
|
||||
for( ; i != item.item_table.end() && current_item != -1 ; ++i )
|
||||
MakeText(**i);
|
||||
|
||||
if( loop < 0 )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Generator::MakeTextNormal(Pattern::Item & item)
|
||||
{
|
||||
if( item.directives.size() != 1 )
|
||||
if( item.directives.empty() )
|
||||
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)
|
||||
{
|
||||
if( result )
|
||||
|
@ -1102,11 +1178,12 @@ void Generator::MakeTextIfany(Pattern::Item & item)
|
|||
|
||||
for( ; d != item.directives.end() ; ++d )
|
||||
{
|
||||
if( !Call(d->name, info1) )
|
||||
// maybe it should only be treated as a false? (when there is no such a function/variable)
|
||||
Info info(*output_stream, empty);
|
||||
|
||||
if( !Call(d->name, info) )
|
||||
return;
|
||||
|
||||
if( info1.result )
|
||||
if( info.res )
|
||||
++how_many_true;
|
||||
}
|
||||
|
||||
|
@ -1121,7 +1198,9 @@ void Generator::MakeTextIfno(Pattern::Item & item)
|
|||
|
||||
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
|
||||
++how_many_true;
|
||||
|
@ -1141,7 +1220,9 @@ void Generator::MakeTextIfone(Pattern::Item & item)
|
|||
|
||||
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
|
||||
++how_many_true;
|
||||
|
@ -1163,8 +1244,10 @@ Functions::Function * function;
|
|||
|
||||
if( function->type == Functions::function )
|
||||
{
|
||||
Call(function, info1, &text);
|
||||
res = info1.result;
|
||||
Info info(*output_stream, text);
|
||||
|
||||
Call(function, info);
|
||||
res = info.res;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1190,21 +1273,28 @@ Functions::Function * function1, * function2;
|
|||
|
||||
if( function1->type == Functions::function && function2->type == Functions::function )
|
||||
{
|
||||
Info info1(*output_stream, empty);
|
||||
Info info2(*output_stream, empty);
|
||||
|
||||
Call(function1, info1);
|
||||
Call(function2, info2);
|
||||
res = (info1.result == info2.result);
|
||||
res = (info1.res == info2.res);
|
||||
}
|
||||
else
|
||||
if( function1->type == Functions::function )
|
||||
{
|
||||
Call(function1, info1, &fun_name2); // only the former is a function
|
||||
res = info1.result;
|
||||
Info info(*output_stream, fun_name2);
|
||||
|
||||
Call(function1, info); // only the former is a function
|
||||
res = info.res;
|
||||
}
|
||||
else
|
||||
if( function2->type == Functions::function )
|
||||
{
|
||||
Call(function2, info2, &fun_name1); // only the latter is a function
|
||||
res = info2.result;
|
||||
Info info(*output_stream, fun_name1);
|
||||
|
||||
Call(function2, info); // only the latter is a function
|
||||
res = info.res;
|
||||
}
|
||||
else
|
||||
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( function->iter == number )
|
||||
result = true;
|
||||
|
||||
// we don't have to set result as false (false is default)
|
||||
result = (function->iter == number);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateMsg(output_stream, "if-index: syntax error");
|
||||
CreateMsg(*output_stream, "if-index: syntax error");
|
||||
|
||||
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)
|
||||
{
|
||||
const int max_loop = 5000;
|
||||
|
||||
if( item.directives.size() != 1 )
|
||||
if( item.directives.empty() )
|
||||
return;
|
||||
|
||||
Functions::Function * function;
|
||||
|
@ -1342,26 +1461,14 @@ void Generator::MakeTextFor(Pattern::Item & item)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
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 )
|
||||
break;
|
||||
function->is_for = true;
|
||||
function->iter = 0;
|
||||
|
||||
if( item.item_table.size() > 0 )
|
||||
MakeText( *item.item_table[0] );
|
||||
}
|
||||
MakeTextForLoop(item, function);
|
||||
|
||||
function->is_for = false;
|
||||
function->iter = 0;
|
||||
|
@ -1376,7 +1483,7 @@ void Generator::MakeTextDefine(Pattern::Item & item)
|
|||
|
||||
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
|
||||
{
|
||||
|
@ -1385,9 +1492,9 @@ void Generator::MakeTextDefine(Pattern::Item & item)
|
|||
if( Find(item.directives[1].name, &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
|
||||
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)
|
||||
{
|
||||
const int max_loop = 50000;
|
||||
|
||||
if( loop == -1 )
|
||||
if( current_item == -1 )
|
||||
return;
|
||||
|
||||
if( ++loop > max_loop )
|
||||
if( ++current_item > max_items )
|
||||
{
|
||||
loop = -1;
|
||||
CreateMsg(output_stream, "Generator exceeded allowed number of elements");
|
||||
current_item = -1;
|
||||
CreateMsg(*output_stream, "Generator exceeded allowed number of elements");
|
||||
return;
|
||||
}
|
||||
|
||||
switch( item.type )
|
||||
{
|
||||
case Pattern::Item::item_text:
|
||||
output_stream << item.text;
|
||||
*output_stream << item.text;
|
||||
break;
|
||||
case Pattern::Item::item_container:
|
||||
MakeTextContainer(item);
|
||||
|
@ -1445,7 +1550,7 @@ void Generator::MakeText(Pattern::Item & item)
|
|||
MakeTextDefine(item);
|
||||
break;
|
||||
case Pattern::Item::item_err:
|
||||
CreateMsg(output_stream, "a wrong directive");
|
||||
CreateMsg(*output_stream, "a wrong directive");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
51
src/ezc.h
51
src/ezc.h
|
@ -164,6 +164,7 @@ private:
|
|||
void ReadDirectiveComment(Item & item);
|
||||
void ReadDirectiveInclude(Item & item);
|
||||
void ReadDirectiveDef(Item & item);
|
||||
void ReadDirectiveNormal(Item::Directive & directive, Item & item);
|
||||
|
||||
void CreateTreeReadItemDirective(Item & item);
|
||||
|
||||
|
@ -185,22 +186,25 @@ private:
|
|||
|
||||
struct Info
|
||||
{
|
||||
// this variables you can set in your function
|
||||
// output stream
|
||||
std::ostringstream & out;
|
||||
//std::string out_string;
|
||||
bool result;
|
||||
|
||||
// in a [is function "text"] statement this is the pointer to "text" object
|
||||
// otherwise this is null pointer
|
||||
const std::string * is;
|
||||
|
||||
// an optional string parameter in a normal statement [user_function "parameter"]
|
||||
// or in "is" statement [is user_function "parameter"]
|
||||
// or in "for" statement [for user_function "parameter"]
|
||||
const std::string & par;
|
||||
|
||||
// this is set by Generator
|
||||
// normally is 0
|
||||
// in a [for] statement it indicates the number of the current iteration (the first is 0)
|
||||
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();
|
||||
};
|
||||
|
||||
|
@ -250,26 +254,36 @@ private:
|
|||
|
||||
class Generator
|
||||
{
|
||||
|
||||
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();
|
||||
|
||||
private:
|
||||
|
||||
std::ostringstream & output_stream;
|
||||
Pattern & pattern;
|
||||
Functions & functions;
|
||||
|
||||
Info info1, info2;
|
||||
int loop;
|
||||
std::ostringstream * output_stream;
|
||||
Pattern * pattern;
|
||||
Functions * functions;
|
||||
|
||||
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);
|
||||
|
||||
|
||||
void Call(Functions::Function * function, Info & info, const std::string * is = 0);
|
||||
bool Call(const std::string & name, Info & info, Functions::Function ** pfun = 0, const std::string * is = 0);
|
||||
void Call(Functions::Function * function, Info & info);
|
||||
bool Call(const std::string & name, Info & info, Functions::Function ** pfun = 0);
|
||||
|
||||
void CallUserFunction(Functions::Function * function, Info & info);
|
||||
void CallVariable(Functions::Function * function, Info & info);
|
||||
|
@ -280,6 +294,7 @@ private:
|
|||
void MakeTextIfno(Pattern::Item & item);
|
||||
void MakeTextIfone(Pattern::Item & item);
|
||||
void MakeTextIfindex(Pattern::Item & item);
|
||||
void MakeTextForLoop(Pattern::Item & item, Functions::Function * function);
|
||||
void MakeTextFor(Pattern::Item & item);
|
||||
void MakeTextContainer(Pattern::Item & item);
|
||||
void MakeTextNormal(Pattern::Item & item);
|
||||
|
|
Loading…
Reference in New Issue