changed: the interface in this version is not the same as previous
added: class Functions, you can define your own set of functions and then put them into the Generator added: variables parser is able to parse the "def" directive: [def variable "value"] [def variable another_variable] [def variable another_function] variables are put into a Functions object added: class Info has a reference to std::ostringstream (out) added: limit for a "for" directive limit for the whole tree (when genereting) this is to protect for a case when someone makes an infinite loop changed: many small changes git-svn-id: svn://ttmath.org/publicrep/ezc/trunk@88 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
bf585d3716
commit
54be9c0489
487
src/ezc.cpp
487
src/ezc.cpp
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007, Tomasz Sowa
|
* Copyright (c) 2007-2008, 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
|
||||||
|
@ -41,21 +41,29 @@ namespace Ezc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
void CreateMsg(std::ostringstream & o, const char * type, const char * arg)
|
||||||
|
{
|
||||||
|
o << "<!-- ezc: " << type << " ";
|
||||||
|
|
||||||
|
if( arg )
|
||||||
|
o << arg << " ";
|
||||||
|
|
||||||
|
o << "-->";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string CreateMsg(const char * type, const char * arg)
|
std::string CreateMsg(const char * type, const char * arg)
|
||||||
{
|
{
|
||||||
std::ostringstream buffer;
|
std::ostringstream buffer;
|
||||||
|
|
||||||
buffer << "<!-- ezc: " << type << " ";
|
CreateMsg(buffer, type, arg);
|
||||||
|
|
||||||
if( arg )
|
|
||||||
buffer << arg << " ";
|
|
||||||
|
|
||||||
buffer << "-->";
|
|
||||||
|
|
||||||
return buffer.str();
|
return buffer.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
this method splits the input file name into a directory and a file name
|
this method splits the input file name into a directory and a file name
|
||||||
e.g
|
e.g
|
||||||
|
@ -64,37 +72,37 @@ return buffer.str();
|
||||||
dir = "/this/is/dummy"
|
dir = "/this/is/dummy"
|
||||||
file = "file.ezc"
|
file = "file.ezc"
|
||||||
*/
|
*/
|
||||||
void SplitUnixDirectory(const char * name, std::string & dir, std::string & file)
|
void SplitUnixDirectory(const char * name, std::string & dir, std::string & file)
|
||||||
{
|
{
|
||||||
dir.clear();
|
dir.clear();
|
||||||
file.clear();
|
file.clear();
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for( i=0 ; name[i] != 0 ; ++i );
|
for( i=0 ; name[i] != 0 ; ++i );
|
||||||
|
|
||||||
if( i == 0 )
|
if( i == 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for( --i ; i>=0 && name[i]!='\\' && name[i]!='/' ; --i );
|
for( --i ; i>=0 && name[i]!='\\' && name[i]!='/' ; --i );
|
||||||
|
|
||||||
if( i < 0 )
|
if( i < 0 )
|
||||||
{
|
{
|
||||||
file.assign(name);
|
file.assign(name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( i == 0 )
|
if( i == 0 )
|
||||||
// we're leaving one '/' in the directory
|
// we're leaving one '/' in the directory
|
||||||
// (we have only the root directory)
|
// (we have only the root directory)
|
||||||
dir.assign(name, 1);
|
dir.assign(name, 1);
|
||||||
else
|
else
|
||||||
dir.assign(name, i);
|
dir.assign(name, i);
|
||||||
|
|
||||||
file.assign(name + i + 1 );
|
file.assign(name + i + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplitUnixDirectory(const std::string & name, std::string & dir, std::string & file)
|
void SplitUnixDirectory(const std::string & name, std::string & dir, std::string & file)
|
||||||
{
|
{
|
||||||
|
@ -234,7 +242,9 @@ return directive;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string Pattern::ReadString()
|
|
||||||
|
|
||||||
|
std::string Pattern::ReadString(bool skip_first_quote)
|
||||||
{
|
{
|
||||||
std::string directive;
|
std::string directive;
|
||||||
|
|
||||||
|
@ -244,7 +254,8 @@ std::string directive;
|
||||||
return directive;
|
return directive;
|
||||||
|
|
||||||
// string is signed by its first character equal (")
|
// string is signed by its first character equal (")
|
||||||
directive += '\"';
|
if( !skip_first_quote )
|
||||||
|
directive += '\"';
|
||||||
|
|
||||||
for( ++itext ; *itext && *itext!='\"' && *itext!='\n' ; ++itext )
|
for( ++itext ; *itext && *itext!='\"' && *itext!='\n' ; ++itext )
|
||||||
directive += *itext;
|
directive += *itext;
|
||||||
|
@ -397,6 +408,27 @@ void Pattern::ReadDirectiveInclude(Item & item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Pattern::ReadDirectiveDef(Item & item)
|
||||||
|
{
|
||||||
|
item.type = Item::item_def;
|
||||||
|
std::string directive = ReadDirective();
|
||||||
|
|
||||||
|
if( !directive.empty() )
|
||||||
|
{
|
||||||
|
item.directives.push_back(directive);
|
||||||
|
|
||||||
|
directive = ReadDirectiveOrString();
|
||||||
|
|
||||||
|
if( !directive.empty() )
|
||||||
|
item.directives.push_back(directive);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( item.directives.size() != 2 )
|
||||||
|
item.type = Item::item_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Pattern::CreateTreeReadItemDirective(Item & item)
|
void Pattern::CreateTreeReadItemDirective(Item & item)
|
||||||
{
|
{
|
||||||
++itext;
|
++itext;
|
||||||
|
@ -427,6 +459,9 @@ void Pattern::CreateTreeReadItemDirective(Item & item)
|
||||||
if( directive == "include" )
|
if( directive == "include" )
|
||||||
ReadDirectiveInclude(item);
|
ReadDirectiveInclude(item);
|
||||||
else
|
else
|
||||||
|
if( directive == "def" )
|
||||||
|
ReadDirectiveDef(item);
|
||||||
|
else
|
||||||
if( directive == "#" )
|
if( directive == "#" )
|
||||||
ReadDirectiveComment(item);
|
ReadDirectiveComment(item);
|
||||||
else
|
else
|
||||||
|
@ -658,13 +693,108 @@ Pattern::Item::~Item()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Info::Info()
|
void Info::Clear()
|
||||||
{
|
{
|
||||||
|
// default settings indicate 'false'
|
||||||
result = false;
|
result = false;
|
||||||
iter = 0;
|
out_string.clear();
|
||||||
|
|
||||||
|
iter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Info::Info(std::ostringstream & o) : out(o)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Info::IsTrue() const
|
||||||
|
{
|
||||||
|
if( result || !out_string.empty() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Info::IsFalse() const
|
||||||
|
{
|
||||||
|
return !IsTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Functions
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
Functions::Function::Function()
|
||||||
|
{
|
||||||
|
type = Functions::variable;
|
||||||
|
user_function = 0;
|
||||||
|
iter = 0;
|
||||||
|
is_for = false;
|
||||||
|
is_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Functions::Insert(const std::string & key, UserFunction ufunction)
|
||||||
|
{
|
||||||
|
Function f;
|
||||||
|
f.type = function;
|
||||||
|
f.user_function = ufunction;
|
||||||
|
|
||||||
|
functions_table[key] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Functions::Insert(const std::string & key, const char * var)
|
||||||
|
{
|
||||||
|
Function f;
|
||||||
|
f.type = variable;
|
||||||
|
f.variable = var;
|
||||||
|
|
||||||
|
functions_table[key] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Functions::Insert(const std::string & key, const std::string & var)
|
||||||
|
{
|
||||||
|
Function f;
|
||||||
|
f.type = variable;
|
||||||
|
f.variable = var;
|
||||||
|
|
||||||
|
functions_table[key] = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Functions::Find(const std::string & key, Function ** fun)
|
||||||
|
{
|
||||||
|
FunctionsTable::iterator i = functions_table.find( key );
|
||||||
|
|
||||||
|
if( i == functions_table.end() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*fun = &(i->second);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Functions::Clear()
|
||||||
|
{
|
||||||
|
functions_table.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Generator
|
* Generator
|
||||||
|
@ -674,70 +804,114 @@ Info::Info()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string & Generator::Generate(Pattern & data)
|
bool Generator::Find(const std::string & key, Functions::Function ** function)
|
||||||
{
|
{
|
||||||
otext.clear();
|
if( !functions.Find(key, function) )
|
||||||
MakeText( data.item_root );
|
{
|
||||||
|
CreateMsg(output_stream, "can't find", key.c_str() );
|
||||||
return otext;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string & Generator::String()
|
|
||||||
|
|
||||||
|
void Generator::CallUserFunction(Functions::Function * function, Info & info)
|
||||||
{
|
{
|
||||||
return otext;
|
// przetestowac to jeszcze !!!! (wczesniej sprawdzenie bylo w Find) !!
|
||||||
|
if( function->is_running )
|
||||||
|
{
|
||||||
|
// recurrences are not allowed
|
||||||
|
CreateMsg(output_stream, "the function is currently running" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function->is_running = true;
|
||||||
|
(function->user_function)(info);
|
||||||
|
function->is_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::Insert(const std::string & key, UserFunction ufunction)
|
|
||||||
{
|
|
||||||
UserInfo ui;
|
|
||||||
ui.user_function = ufunction;
|
|
||||||
ui.iter = 0;
|
|
||||||
|
|
||||||
user_info_table.insert( std::make_pair(key, ui) );
|
void Generator::CallVariable(Functions::Function * function, Info & info)
|
||||||
|
{
|
||||||
|
info.out_string = function->variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Generator::Call(Functions::Function * function, Info & info)
|
||||||
|
{
|
||||||
|
info.Clear();
|
||||||
|
info.iter = function->iter;
|
||||||
|
|
||||||
|
if( function->type == Functions::function )
|
||||||
|
CallUserFunction(function, info);
|
||||||
|
else
|
||||||
|
CallVariable(function, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return: true if a function or variable was found and called
|
||||||
|
bool Generator::Call(const std::string & name, Info & info, Functions::Function ** pfun)
|
||||||
|
{
|
||||||
|
Functions::Function * function;
|
||||||
|
|
||||||
|
if( Find(name, &function) )
|
||||||
|
{
|
||||||
|
Call(function, info);
|
||||||
|
|
||||||
|
if( pfun )
|
||||||
|
*pfun = 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Generator::MakeTextContainer(Pattern::Item & item)
|
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() ; ++i )
|
||||||
MakeText(**i);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Generator::Find(const std::string & key, UserInfo ** user_info)
|
|
||||||
{
|
|
||||||
UserInfoTable::iterator i = user_info_table.find( key );
|
|
||||||
|
|
||||||
if( i == user_info_table.end() )
|
|
||||||
{
|
{
|
||||||
otext += CreateMsg("can't find", key.c_str() );
|
MakeText(**i);
|
||||||
return false;
|
|
||||||
|
if( loop < 0 )
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
*user_info = &(i->second);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Generator::MakeTextNormal(Pattern::Item & item)
|
void Generator::MakeTextNormal(Pattern::Item & item)
|
||||||
{
|
{
|
||||||
if( item.directives.size() != 1 )
|
if( item.directives.size() != 1 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UserInfo * user_info;
|
Call(item.directives[0], info1);
|
||||||
|
|
||||||
if( Find(item.directives[0], &user_info) )
|
if( !info1.out_string.empty() )
|
||||||
{
|
output_stream << info1.out_string;
|
||||||
Info info;
|
|
||||||
(user_info->user_function)(info);
|
|
||||||
|
|
||||||
otext += info.text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -764,18 +938,11 @@ void Generator::MakeTextIfany(Pattern::Item & item)
|
||||||
|
|
||||||
for( ; d != item.directives.end() ; ++d )
|
for( ; d != item.directives.end() ; ++d )
|
||||||
{
|
{
|
||||||
UserInfo * user_info;
|
if( !Call(*d, info1) )
|
||||||
|
|
||||||
if( !Find(*d, &user_info) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
Info info;
|
if( info1.IsTrue() )
|
||||||
(user_info->user_function)(info);
|
|
||||||
|
|
||||||
if( !info.text.empty() || info.result )
|
|
||||||
++how_many_true;
|
++how_many_true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeTextIf_go(item, how_many_true == item.directives.size() );
|
MakeTextIf_go(item, how_many_true == item.directives.size() );
|
||||||
|
@ -789,15 +956,7 @@ void Generator::MakeTextIfone(Pattern::Item & item)
|
||||||
|
|
||||||
for( ; d != item.directives.end() ; ++d )
|
for( ; d != item.directives.end() ; ++d )
|
||||||
{
|
{
|
||||||
UserInfo * user_info;
|
if( Call(*d, info1) && info1.IsTrue() )
|
||||||
|
|
||||||
if( !Find(*d, &user_info) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Info info;
|
|
||||||
(user_info->user_function)(info);
|
|
||||||
|
|
||||||
if( !info.text.empty() || info.result )
|
|
||||||
++how_many_true;
|
++how_many_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -805,32 +964,28 @@ void Generator::MakeTextIfone(Pattern::Item & item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Generator::MakeTextIs(Pattern::Item & item)
|
void Generator::MakeTextIs(Pattern::Item & item)
|
||||||
{
|
{
|
||||||
if( item.directives.size() != 2 )
|
if( item.directives.size() != 2 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UserInfo * user_info;
|
if( !Call(item.directives[0], info1) )
|
||||||
|
|
||||||
if( !Find(item.directives[0], &user_info) )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
Info info1, info2;
|
|
||||||
(user_info->user_function)(info1);
|
|
||||||
|
|
||||||
if( !item.directives[1].empty() && item.directives[1][0]=='\"' )
|
if( !item.directives[1].empty() && item.directives[1][0]=='\"' )
|
||||||
{
|
{
|
||||||
if( std::strcmp(info1.text.c_str(), item.directives[1].c_str()+1) == 0 )
|
// second directive is a string
|
||||||
|
if( std::strcmp(info1.out_string.c_str(), item.directives[1].c_str()+1) == 0 )
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( Find(item.directives[1], &user_info) )
|
if( Call(item.directives[1], info2) )
|
||||||
{
|
{
|
||||||
(user_info->user_function)(info2);
|
if( info1.result==info2.result && info1.out_string==info2.out_string )
|
||||||
|
|
||||||
if( info1.result==info2.result && info1.text==info2.text )
|
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -839,7 +994,7 @@ void Generator::MakeTextIs(Pattern::Item & item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Generator::MakeTextIfindexnumber(Pattern::Item & item, UserInfo * user_info, bool & result)
|
bool Generator::MakeTextIfindexnumber(Pattern::Item & item, Functions::Function * function, bool & result)
|
||||||
{
|
{
|
||||||
if( item.directives.size() != 2 )
|
if( item.directives.size() != 2 )
|
||||||
return false;
|
return false;
|
||||||
|
@ -851,12 +1006,14 @@ bool Generator::MakeTextIfindexnumber(Pattern::Item & item, UserInfo * user_info
|
||||||
|
|
||||||
if( *last_char == '\0' )
|
if( *last_char == '\0' )
|
||||||
{
|
{
|
||||||
if( user_info->iter == number )
|
if( function->iter == number )
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
|
// we don't have to set result as false (false is default)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
otext += CreateMsg("if-index: syntax error");
|
CreateMsg(output_stream, "if-index: syntax error");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -870,33 +1027,37 @@ void Generator::MakeTextIfindex(Pattern::Item & item)
|
||||||
if( item.directives.size() != 2 )
|
if( item.directives.size() != 2 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UserInfo * user_info;
|
// we actually don't call a function (or variable) here
|
||||||
|
// but only reading an iteration index
|
||||||
|
|
||||||
|
Functions::Function * function;
|
||||||
|
|
||||||
|
if( !Find(item.directives[0], &function) )
|
||||||
|
return;
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if( !Find(item.directives[0], &user_info) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
if( item.directives[1] == "odd" )
|
if( item.directives[1] == "odd" )
|
||||||
{
|
{
|
||||||
if( ( user_info->iter & 1) == 1 )
|
if( (function->iter & 1) == 1 )
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if( item.directives[1] == "even" )
|
if( item.directives[1] == "even" )
|
||||||
{
|
{
|
||||||
if( ( user_info->iter & 1) == 0 )
|
if( (function->iter & 1) == 0 )
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if( item.directives[1] == "first" )
|
if( item.directives[1] == "first" )
|
||||||
{
|
{
|
||||||
if( user_info->iter == 0 )
|
if( function->iter == 0 )
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( !MakeTextIfindexnumber(item, user_info, result) )
|
if( !MakeTextIfindexnumber(item, function, result) )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,42 +1065,94 @@ void Generator::MakeTextIfindex(Pattern::Item & item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Generator::MakeTextFor(Pattern::Item & item)
|
void Generator::MakeTextFor(Pattern::Item & item)
|
||||||
{
|
{
|
||||||
|
const int max_loop = 3000;
|
||||||
|
|
||||||
if( item.directives.size() != 1 )
|
if( item.directives.size() != 1 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UserInfo * user_info;
|
Functions::Function * function;
|
||||||
|
|
||||||
if( !Find(item.directives[0], &user_info) )
|
if( !Find(item.directives[0], &function) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if( function->is_for )
|
||||||
Info info;
|
|
||||||
user_info->iter = 0;
|
|
||||||
|
|
||||||
while( true )
|
|
||||||
{
|
{
|
||||||
(user_info->user_function)(info);
|
CreateMsg(output_stream, item.directives[0].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].c_str(), "function exceeded a limit for a [for] statement");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Call(function, info1);
|
||||||
|
|
||||||
if( info.text.empty() && !info.result )
|
if( info1.IsFalse() )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if( item.item_table.size() > 0 )
|
if( item.item_table.size() > 0 )
|
||||||
MakeText( *item.item_table[0] );
|
MakeText( *item.item_table[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
function->is_for = false;
|
||||||
|
function->iter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
++info.iter;
|
|
||||||
user_info->iter = info.iter;
|
|
||||||
|
void Generator::MakeTextDefine(Pattern::Item & item)
|
||||||
|
{
|
||||||
|
if( item.directives.size() != 2 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( !item.directives[1].empty() && item.directives[1][0]=='\"' )
|
||||||
|
{
|
||||||
|
// second directive is a string
|
||||||
|
functions.Insert(item.directives[0], item.directives[1].c_str() + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Functions::Function * function;
|
||||||
|
|
||||||
|
if( Find(item.directives[1], &function) )
|
||||||
|
{
|
||||||
|
if( function->type == Functions::function )
|
||||||
|
functions.Insert(item.directives[0], function->user_function);
|
||||||
|
else
|
||||||
|
functions.Insert(item.directives[0], function->variable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Generator::MakeText(Pattern::Item & item)
|
void Generator::MakeText(Pattern::Item & item)
|
||||||
{
|
{
|
||||||
|
const int max_loop = 10000;
|
||||||
|
|
||||||
|
if( loop == -1 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( ++loop > max_loop )
|
||||||
|
{
|
||||||
|
loop = -1;
|
||||||
|
CreateMsg(output_stream, "Generator exceeded allowed number of elements");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch( item.type )
|
switch( item.type )
|
||||||
{
|
{
|
||||||
case Pattern::Item::item_text:
|
case Pattern::Item::item_text:
|
||||||
otext += item.text;
|
output_stream << item.text;
|
||||||
break;
|
break;
|
||||||
case Pattern::Item::item_container:
|
case Pattern::Item::item_container:
|
||||||
MakeTextContainer(item);
|
MakeTextContainer(item);
|
||||||
|
@ -962,8 +1175,11 @@ void Generator::MakeText(Pattern::Item & item)
|
||||||
case Pattern::Item::item_for:
|
case Pattern::Item::item_for:
|
||||||
MakeTextFor(item);
|
MakeTextFor(item);
|
||||||
break;
|
break;
|
||||||
|
case Pattern::Item::item_def:
|
||||||
|
MakeTextDefine(item);
|
||||||
|
break;
|
||||||
case Pattern::Item::item_err:
|
case Pattern::Item::item_err:
|
||||||
otext += CreateMsg("a wrong directive");
|
CreateMsg(output_stream, "a wrong directive");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -971,12 +1187,5 @@ void Generator::MakeText(Pattern::Item & item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Generator::Clear()
|
|
||||||
{
|
|
||||||
user_info_table.clear();
|
|
||||||
otext.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace Ezc
|
} // namespace Ezc
|
||||||
|
|
||||||
|
|
114
src/ezc.h
114
src/ezc.h
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2007, Tomasz Sowa
|
* Copyright (c) 2007-2008, 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
|
||||||
|
@ -56,10 +56,14 @@
|
||||||
namespace Ezc
|
namespace Ezc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
void CreateMsg(std::ostringstream & o, const char * type, const char * arg = 0);
|
||||||
std::string CreateMsg(const char * type, const char * arg = 0);
|
std::string CreateMsg(const char * type, const char * arg = 0);
|
||||||
void SplitUnixDirectory(const char * name, std::string & dir, std::string & file);
|
void SplitUnixDirectory(const char * name, std::string & dir, std::string & file);
|
||||||
void SplitUnixDirectory(const std::string & name, std::string & dir, std::string & file);
|
void SplitUnixDirectory(const std::string & name, std::string & dir, std::string & file);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Pattern
|
class Pattern
|
||||||
{
|
{
|
||||||
|
@ -71,13 +75,17 @@ public:
|
||||||
|
|
||||||
struct Item
|
struct Item
|
||||||
{
|
{
|
||||||
|
// change the name to 'Type'
|
||||||
enum ItemType
|
enum ItemType
|
||||||
{
|
{
|
||||||
item_none, item_container, item_text, item_ifany, item_for,
|
item_none, item_container, item_text, item_ifany, item_for,
|
||||||
item_else, item_end, item_err, item_normal, item_ifindex,
|
item_else, item_end, item_err, item_normal, item_ifindex,
|
||||||
item_include, item_is, item_ifone, item_comment
|
item_include, item_is, item_ifone, item_comment, item_def
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ItemType type;
|
ItemType type;
|
||||||
std::string text;
|
std::string text;
|
||||||
std::vector<Item*> item_table;
|
std::vector<Item*> item_table;
|
||||||
|
@ -111,7 +119,7 @@ private:
|
||||||
void SkipWhiteCharacters();
|
void SkipWhiteCharacters();
|
||||||
|
|
||||||
std::string ReadDirective();
|
std::string ReadDirective();
|
||||||
std::string ReadString();
|
std::string ReadString(bool skip_first_quote = false);
|
||||||
std::string ReadDirectiveOrString();
|
std::string ReadDirectiveOrString();
|
||||||
|
|
||||||
void CreateTreeReadItemDirectiveCheckEnding(Item & item);
|
void CreateTreeReadItemDirectiveCheckEnding(Item & item);
|
||||||
|
@ -123,6 +131,7 @@ private:
|
||||||
void ReadDirectiveFor(Item & item);
|
void ReadDirectiveFor(Item & item);
|
||||||
void ReadDirectiveComment(Item & item);
|
void ReadDirectiveComment(Item & item);
|
||||||
void ReadDirectiveInclude(Item & item);
|
void ReadDirectiveInclude(Item & item);
|
||||||
|
void ReadDirectiveDef(Item & item);
|
||||||
|
|
||||||
void CreateTreeReadItemDirective(Item & item);
|
void CreateTreeReadItemDirective(Item & item);
|
||||||
|
|
||||||
|
@ -138,45 +147,101 @@ private:
|
||||||
}; // Pattern
|
}; // Pattern
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct Info
|
struct Info
|
||||||
{
|
{
|
||||||
std::string text;
|
// this variables you can set in your function
|
||||||
|
std::ostringstream & out;
|
||||||
|
std::string out_string;
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
|
// 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;
|
int iter;
|
||||||
|
|
||||||
Info();
|
|
||||||
|
Info(std::ostringstream & o);
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
bool IsTrue() const;
|
||||||
|
bool IsFalse() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Functions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef void (*UserFunction)(Info &);
|
||||||
|
enum Type { function, variable };
|
||||||
|
|
||||||
|
struct Function
|
||||||
|
{
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
UserFunction user_function;
|
||||||
|
std::string variable;
|
||||||
|
|
||||||
|
int iter;
|
||||||
|
bool is_for; // true if is used by a [for] statement
|
||||||
|
bool is_running; // true if this function (if is) is currently running
|
||||||
|
|
||||||
|
Function();
|
||||||
|
};
|
||||||
|
|
||||||
|
void Insert(const std::string & key, UserFunction ufunction); // inserting a function
|
||||||
|
void Insert(const std::string & key, const char * var); // inserting a variable
|
||||||
|
void Insert(const std::string & key, const std::string & var); // inserting a variable
|
||||||
|
|
||||||
|
bool Find(const std::string & key, Function ** fun);
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::map<std::string, Function> FunctionsTable;
|
||||||
|
FunctionsTable functions_table;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Generator
|
class Generator
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
typedef void (*UserFunction)(Info &);
|
|
||||||
|
|
||||||
struct UserInfo
|
|
||||||
{
|
|
||||||
UserFunction user_function;
|
|
||||||
int iter;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<std::string, UserInfo> UserInfoTable;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void Insert(const std::string & key, UserFunction ufunction);
|
Generator(std::ostringstream &, Pattern & data, Functions & functions);
|
||||||
std::string & Generate(Pattern & data);
|
void Generate();
|
||||||
std::string & String();
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
UserInfoTable user_info_table;
|
std::ostringstream & output_stream;
|
||||||
std::string otext;
|
Pattern & pattern;
|
||||||
|
Functions & functions;
|
||||||
bool Find(const std::string & key, UserInfo ** user_info);
|
|
||||||
|
Info info1, info2;
|
||||||
|
int loop;
|
||||||
|
|
||||||
|
bool Find(const std::string & key, Functions::Function ** function);
|
||||||
|
|
||||||
|
|
||||||
|
bool Call(const std::string & name, Info & info, Functions::Function ** pfun = 0);
|
||||||
|
void Call(Functions::Function * function, Info & info);
|
||||||
|
|
||||||
|
void CallUserFunction(Functions::Function * function, Info & info);
|
||||||
|
void CallVariable(Functions::Function * function, Info & info);
|
||||||
|
|
||||||
void MakeTextIf_go(Pattern::Item & item, bool result);
|
void MakeTextIf_go(Pattern::Item & item, bool result);
|
||||||
bool MakeTextIfindexnumber(Pattern::Item & item, UserInfo * user_info, bool & result);
|
bool MakeTextIfindexnumber(Pattern::Item & item, Functions::Function * function, bool & result);
|
||||||
void MakeTextIfany(Pattern::Item & item);
|
void MakeTextIfany(Pattern::Item & item);
|
||||||
void MakeTextIfone(Pattern::Item & item);
|
void MakeTextIfone(Pattern::Item & item);
|
||||||
void MakeTextIfindex(Pattern::Item & item);
|
void MakeTextIfindex(Pattern::Item & item);
|
||||||
|
@ -184,6 +249,7 @@ private:
|
||||||
void MakeTextContainer(Pattern::Item & item);
|
void MakeTextContainer(Pattern::Item & item);
|
||||||
void MakeTextNormal(Pattern::Item & item);
|
void MakeTextNormal(Pattern::Item & item);
|
||||||
void MakeTextIs(Pattern::Item & item);
|
void MakeTextIs(Pattern::Item & item);
|
||||||
|
void MakeTextDefine(Pattern::Item & item);
|
||||||
void MakeText(Pattern::Item & item);
|
void MakeText(Pattern::Item & item);
|
||||||
|
|
||||||
}; // Generator
|
}; // Generator
|
||||||
|
|
Loading…
Reference in New Issue