Browse Source

Add directives in config files for loading modules and setup search paths for modules and includes.

test
Michael Uleysky 9 years ago
parent
commit
7e68629fbe
  1. 3
      include/common.h
  2. 7
      include/globals.h
  3. 3
      include/parser.h
  4. 2
      src/Makefile
  5. 78
      src/globals.cpp
  6. 2
      src/init.cpp
  7. 18
      src/parser/grammatical.y
  8. 52
      src/parser/lexical.l

3
include/common.h

@ -255,11 +255,12 @@ public:
ObjectList* PushBack(ObjectBase* p) {vals->push_back(p); return this;} ObjectList* PushBack(ObjectBase* p) {vals->push_back(p); return this;}
}; };
typedef ObjectBase* (*Func)(const ObjectList*); typedef ObjectBase* (*Func)(const ObjectList*);
typedef int (*ModuleInitFunc)(const void*);
extern "C" { extern "C" {
EXPORT void RegisterFunction(const std::string& name, Func func); EXPORT void RegisterFunction(const std::string& name, Func func);
EXPORT int LoadModule(const std::string& name, const void* p, const std::string& modname="");
} }
#endif #endif

7
include/globals.h

@ -1,8 +1,9 @@
#ifndef GLOBALS_H #ifndef GLOBALS_H
#define GLOBALS_H #define GLOBALS_H
#include "dlfcn.h"
#include <map> #include <map>
#include <vector>
#include <string> #include <string>
#include <vector>
#include "object.h" #include "object.h"
// Variables definitions // Variables definitions
@ -20,6 +21,10 @@ extern G_toType G_tosave;
// List of objects to print // List of objects to print
extern G_toType G_toprint; extern G_toType G_toprint;
// Loaded modules
typedef std::vector<void*> G_libsType;
extern G_libsType G_libs;
void ClearGlobals(); void ClearGlobals();
bool Save(const ObjectList* input); bool Save(const ObjectList* input);

3
include/parser.h

@ -1,7 +1,7 @@
#ifndef PARSER_PARSER_H #ifndef PARSER_PARSER_H
#define PARSER_PARSER_H #define PARSER_PARSER_H
#include <string>
#include <stack> #include <stack>
#include <string>
#include <stdio.h> #include <stdio.h>
// State of lexical parser (filename and position in file) // State of lexical parser (filename and position in file)
@ -15,6 +15,7 @@ struct lexical_state
// Container for "static" parameters of lexical parser // Container for "static" parameters of lexical parser
struct lexical_extra struct lexical_extra
{ {
std::string includedirs,moduledirs;
struct lexical_state state; struct lexical_state state;
unsigned int maxinclevel; unsigned int maxinclevel;
int retcode; int retcode;

2
src/Makefile

@ -1,7 +1,7 @@
OPTFLAGS=-O2 -flto -g OPTFLAGS=-O2 -flto -g
EXPORTFLAGS=-fvisibility=hidden -fpic -Wl,--export-dynamic EXPORTFLAGS=-fvisibility=hidden -fpic -Wl,--export-dynamic
CPPFLAGS=-std=gnu++11 -I../include CPPFLAGS=-std=gnu++11 -I../include
LIBSFLAGS=-lpthread LIBSFLAGS=-ldl -lpthread
WARNFLAGS=-Wall WARNFLAGS=-Wall
CFLAGS=$(OPTFLAGS) $(EXPORTFLAGS) $(WARNFLAGS) $(CPPFLAGS) CFLAGS=$(OPTFLAGS) $(EXPORTFLAGS) $(WARNFLAGS) $(CPPFLAGS)

78
src/globals.cpp

@ -1,6 +1,5 @@
#include "globals.h" #include "globals.h"
// Variables definitions // Variables definitions
G_varsType G_vars; G_varsType G_vars;
@ -13,17 +12,94 @@ G_toType G_tosave;
// List of objects to print // List of objects to print
G_toType G_toprint; G_toType G_toprint;
// Loaded modules
G_libsType G_libs;
void ClearGlobals() void ClearGlobals()
{ {
for(auto& it:G_vars) delete it.second; for(auto& it:G_vars) delete it.second;
for(auto& it:G_tosave) delete it; for(auto& it:G_tosave) delete it;
for(auto& it:G_toprint) delete it; for(auto& it:G_toprint) delete it;
for(auto& it:G_libs) dlclose(it);
G_vars.clear(); G_vars.clear();
G_tosave.clear(); G_tosave.clear();
G_toprint.clear(); G_toprint.clear();
} }
int LoadModule(const std::string& name, const void* p, const std::string& modname)
{
const std::string spath=*(reinterpret_cast<const std::string*>(p));
// Load module
void* handle;
void* initfunc;
std::string initname;
if(0!=modname.size()) initname=modname;
else
{
// Remove directory name, if present
initname=name.substr((name.rfind('/')!=std::string::npos)?(name.rfind('/')+1):0,std::string::npos);
// Remove ".so" on the end of string
if(initname.rfind(".so")!=std::string::npos) initname.erase(initname.rfind(".so"),std::string::npos);
}
initname+="_module_init";
// Check if module is statically linked or already loaded: dlopen'ed the main program
handle=dlopen(0,RTLD_LAZY|RTLD_GLOBAL);
if(0==handle)
{
COUT(ERROR)<<std::endl<<"Something wrong: can't dlopen the main program"<<std::endl;
return 1;
}
initfunc=dlsym(handle,initname.c_str());
if(0==initfunc) // We not find it
{
if('/'==name[0]) // Absolute path
{
handle=dlopen(name.c_str(),RTLD_LAZY|RTLD_GLOBAL);
if(0==handle) handle=dlopen((name+".so").c_str(),RTLD_LAZY|RTLD_GLOBAL);
}
else // Relative path
{
std::string curpath;
size_t bpos=0,epos;
// Check in spath
do
{
epos=spath.find(':',bpos);
curpath=spath.substr(bpos,(std::string::npos==epos)?epos:(epos-bpos));
handle=dlopen((curpath+name).c_str(),RTLD_LAZY|RTLD_GLOBAL);
if(0!=handle) break;
handle=dlopen((curpath+name+".so").c_str(),RTLD_LAZY|RTLD_GLOBAL);
if(0!=handle) break;
bpos=epos+1;
} while(std::string::npos!=epos);
}
if(0==handle)
{
COUT(ERROR)<<std::endl<<"Can't dlopen module "<<name<<std::endl;
return 1;
}
G_libs.push_back(handle);
initfunc=dlsym(handle,initname.c_str());
}
if(0==initfunc)
{
COUT(ERROR)<<std::endl<<"Can't find initialising function "<<initname<<" in module "<<name<<std::endl;
return 1;
}
int ret=(*reinterpret_cast<ModuleInitFunc>(initfunc))(p);
if(0!=ret) COUT(ERROR)<<std::endl<<"Initialising function "<<initname<<" of module "<<name<<" returns error "<<ret<<std::endl;
return ret;
}
void RegisterFunction(const std::string& name, Func func) void RegisterFunction(const std::string& name, Func func)
{ {
G_funcs.emplace(name,func); G_funcs.emplace(name,func);

2
src/init.cpp

@ -92,6 +92,8 @@ int ParseConfigFile(const char* config)
extra.state.curdir=cwd; extra.state.curdir=cwd;
free(cwd); free(cwd);
extra.ParsePath(config); extra.ParsePath(config);
// Search paths begin from working directory
extra.includedirs=extra.moduledirs="./";
conflex_init_extra(&extra,&scanner); conflex_init_extra(&extra,&scanner);
confset_in(conffd,scanner); confset_in(conffd,scanner);

18
src/parser/grammatical.y

@ -51,6 +51,7 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str)
} }
%token ASSIGN OBRACE CBRACE ENDL DELIM %token ASSIGN OBRACE CBRACE ENDL DELIM
%token DIR_USE DIR_INCLUDEPATH DIR_MODULEPATH DIR_AS
%token <r> REAL %token <r> REAL
%token <b> BOOL %token <b> BOOL
@ -82,8 +83,25 @@ inline void conferror(const YYLTYPE& locp, yyscan_t sc, const std::string& str)
input: input:
%empty {COUT(DEBUG)<<"Empty input\n";} %empty {COUT(DEBUG)<<"Empty input\n";}
| input line {COUT(DEBUG)<<" input line\n";} | input line {COUT(DEBUG)<<" input line\n";}
| input dirline {COUT(DEBUG)<<" input dirline\n";}
; ;
dirline:
DIR_INCLUDEPATH STRING {COUT(DEBUG)<<" DIR_INCLUDEPATH STRING\n"; confget_extra(scanner)->includedirs+=":"+*$2+(('/'==$2->back())?"":"/"); delete $2;}
| DIR_MODULEPATH STRING {COUT(DEBUG)<<" DIR_MODULEPATH STRING\n"; confget_extra(scanner)->moduledirs+=":"+*$2+(('/'==$2->back())?"":"/"); delete $2;}
| DIR_USE STRING {COUT(DEBUG)<<" DIR_USE STRING\n";
int ret=LoadModule(*$2,&confget_extra(scanner)->moduledirs);
if(0!=ret) conferror(@1,scanner," fail to load module "+(*$2));
delete $2;
if(0!=ret) YYABORT;
}
| DIR_USE STRING DIR_AS STRING {COUT(DEBUG)<<" DIR_USE STRING DIR_AS STRING\n";
int ret=LoadModule(*$2,&confget_extra(scanner)->moduledirs,*$4);
if(0!=ret) conferror(@1,scanner," fail to load module "+(*$2));
delete $2; delete $4;
if(0!=ret) YYABORT;
}
line: line:
NAME ASSIGN object ENDL {COUT(DEBUG)<<" NAME ASSIGN object ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;} NAME ASSIGN object ENDL {COUT(DEBUG)<<" NAME ASSIGN object ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;}
| NAME ASSIGN list ENDL {COUT(DEBUG)<<" NAME ASSIGN list ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;} | NAME ASSIGN list ENDL {COUT(DEBUG)<<" NAME ASSIGN list ENDL\n"; if(G_vars.count(*$1)!=0) delete G_vars[*$1]; G_vars[*$1]=$3; delete $1;}

52
src/parser/lexical.l

@ -13,8 +13,10 @@
%x PSTRING %x PSTRING
%x PARSE %x PARSE
%x INCLUDE %x INCLUDE
%x PREPROC
%{ %{
#include <algorithm>
#include "common.h" #include "common.h"
#include "parser.h" #include "parser.h"
// flex use register keyword, but it deprecated in C++11. // flex use register keyword, but it deprecated in C++11.
@ -41,30 +43,55 @@ std::string str;
%} %}
%% %%
<PARSE,INITIAL>@include[ \t]*\" yy_push_state(INCLUDE,yyscanner); str.erase(); yynextsym; <PARSE,INITIAL>@[Ii][Nn][Cc][Ll][Uu][Dd][Ee][ \t]*\" yy_push_state(INCLUDE,yyscanner); str.erase(); yynextsym;
@ BEGIN(PREPROC); yynextsym;
<PREPROC>[a-zA-Z]* {
yynextsym; str=yytext; transform(str.begin(),str.end(),str.begin(),::tolower);
if("use"==str) return DIR_USE;
if("includepath"==str) return DIR_INCLUDEPATH;
if("modulepath"==str) return DIR_MODULEPATH;
if("as"==str) return DIR_AS;
COUT(WARNING)<<std::endl<<"Unknown directive "<<str<<", ignoring"<<std::endl;
}
<INCLUDE>\" { <INCLUDE>\" {
if(yyextra->state.inclevel>=yyextra->maxinclevel) yyerrormessage("maximal include level reached",-1); if(yyextra->state.inclevel>=yyextra->maxinclevel) yyerrormessage("maximal include level reached",-1);
FILE* fd; FILE* fd;
std::string fullname;
// yyextra->curdir is directory with currently scanned file // yyextra->curdir is directory with currently scanned file
// !!!NONPORTABLE!!! // !!!NONPORTABLE!!!
if('/'==str[0]) fd=fopen(str.c_str(),"r"); // absolute path fullname=str;
if('/'==fullname[0]) fd=fopen(fullname.c_str(),"r"); // absolute path
else else
{ {
// first, try to search file in working directory // first, try to search in directory with currently scanned file
fd=fopen(str.c_str(),"r"); fullname=yyextra->state.curdir+str;
// if fail, try to search in directory with currently scanned file fd=fopen(fullname.c_str(),"r");
if(fd==0) fd=fopen((yyextra->state.curdir+str).c_str(),"r"); // if fail, try to search file in includedirs
if(0==fd)
{
std::string curpath;
size_t bpos=0,epos;
do
{
epos=yyextra->includedirs.find(':',bpos);
curpath=yyextra->includedirs.substr(bpos,(std::string::npos==epos)?epos:(epos-bpos));
fullname=curpath+str;
fd=fopen(fullname.c_str(),"r");
if(0!=fd) break;
bpos=epos+1;
} while(std::string::npos!=epos);
}
} }
if(fd==0) yyerrormessage("can't open file "+str,-1); if(0==fd) yyerrormessage("can't open file "+str,-1);
yynextsym; yynextsym;
yyextra->fds.push(fd); yyextra->fds.push(fd);
yyextra->states.push(yyextra->state); yyextra->states.push(yyextra->state);
COUT(DEBUG)<<std::endl<<"Include "<<str<<std::endl; COUT(DEBUG)<<std::endl<<"Include "<<str<<std::endl;
yyextra->state.inclevel++; yyextra->state.inclevel++;
yyextra->ParsePath(str); yyextra->ParsePath(fullname);
yyextra->state.curline=1; yyextra->state.curline=1;
yyextra->state.curpos=yyextra->state.curoffset=0; yyextra->state.curpos=yyextra->state.curoffset=0;
yylloc_param->filename=yyextra->state.curdir+yyextra->state.filename; yylloc_param->filename=yyextra->state.curdir+yyextra->state.filename;
@ -86,15 +113,16 @@ std::string str;
<PARSE>, COUT(MOREDEBUG)<<" DELIM()"; setyyllocp; yynextsym; return DELIM; <PARSE>, COUT(MOREDEBUG)<<" DELIM()"; setyyllocp; yynextsym; return DELIM;
<PARSE>[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<<yytext<<")"; yylval_param->str=new std::string(yytext); setyyllocp; yynextsym; return IDENTIFIER; <PARSE>[a-zA-Z][a-zA-Z0-9_]* COUT(MOREDEBUG)<<" IDENTIFIER("<<yytext<<")"; yylval_param->str=new std::string(yytext); setyyllocp; yynextsym; return IDENTIFIER;
<PARSE>\. COUT(MOREDEBUG)<<" DOT()"; setyyllocp; yynextsym; return yytext[0]; <PARSE>\. COUT(MOREDEBUG)<<" DOT()"; setyyllocp; yynextsym; return yytext[0];
<PARSE,INITIAL>[ \t]+ yynextsym; <PARSE,PREPROC,INITIAL>[ \t]+ yynextsym;
<PARSE,INITIAL>\n yynextline; <PARSE,INITIAL>\n yynextline;
<PREPROC>\n BEGIN(0); yynextline;
<PARSE,INITIAL>\#.* yynextsym; <PARSE,INITIAL>\#.* yynextsym;
<PARSE>\" BEGIN(PSTRING); str.erase(); yyextra->states.push(yyextra->state); yynextsym; <PARSE,PREPROC>\" yy_push_state(PSTRING,yyscanner); str.erase(); yyextra->states.push(yyextra->state); yynextsym;
<PARSE,INITIAL>. yyerrormessage(std::string("unknown symbol ")+yytext+" at position "+std::to_string(yyextra->state.curpos),-1); <PARSE,PREPROC,INITIAL>. yyerrormessage(std::string("unknown symbol ")+yytext+" at position "+std::to_string(yyextra->state.curpos),-1);
<PSTRING,INCLUDE>\\\\ str+='\\'; yynextsym; <PSTRING,INCLUDE>\\\\ str+='\\'; yynextsym;
<PSTRING,INCLUDE>\\\" str+='\"'; yynextsym; <PSTRING,INCLUDE>\\\" str+='\"'; yynextsym;
<PSTRING>\n str+=yytext[0]; yynextline; <PSTRING>\n str+=yytext[0]; yynextline;
<PSTRING>\" BEGIN(PARSE); COUT(MOREDEBUG)<<" STRING("<<str<<")"; yylval_param->str=new std::string(str); {struct lexical_state prstate=yyextra->states.top(); yyextra->states.pop(); yylloc_param->first_line=prstate.curline; yylloc_param->last_line=yyextra->state.curline; yylloc_param->first_column=prstate.curpos; yylloc_param->last_column=yyextra->state.curpos+yyleng;}; yynextsym; return STRING; <PSTRING>\" yy_pop_state(yyscanner); COUT(MOREDEBUG)<<" STRING("<<str<<")"; yylval_param->str=new std::string(str); {struct lexical_state prstate=yyextra->states.top(); yyextra->states.pop(); yylloc_param->first_line=prstate.curline; yylloc_param->last_line=yyextra->state.curline; yylloc_param->first_column=prstate.curpos; yylloc_param->last_column=yyextra->state.curpos+yyleng;}; yynextsym; return STRING;
<PSTRING,INCLUDE>. str+=yytext[0]; yynextsym; <PSTRING,INCLUDE>. str+=yytext[0]; yynextsym;
<PSTRING,INCLUDE><<EOF>> yyextra->states.pop(); yyerrormessage("unclosed quote",-1); <PSTRING,INCLUDE><<EOF>> yyextra->states.pop(); yyerrormessage("unclosed quote",-1);
<<EOF>> yypop_buffer_state(yyscanner); if(0!=YY_CURRENT_BUFFER) {yyextra->state=yyextra->states.top(); yyextra->states.pop(); fclose(yyextra->fds.top()); yyextra->fds.pop(); yylloc_param->filename=yyextra->state.curdir+yyextra->state.filename;} else yyterminate(0); <<EOF>> yypop_buffer_state(yyscanner); if(0!=YY_CURRENT_BUFFER) {yyextra->state=yyextra->states.top(); yyextra->states.pop(); fclose(yyextra->fds.top()); yyextra->fds.pop(); yylloc_param->filename=yyextra->state.curdir+yyextra->state.filename;} else yyterminate(0);

Loading…
Cancel
Save