implement internal variable structure

This commit is contained in:
zawwz 2021-01-20 11:49:32 +01:00
parent 7114a39fe3
commit 2ffe4ddf2f
8 changed files with 148 additions and 94 deletions

View file

@ -23,6 +23,10 @@
#define SPECIAL_VARS "!#*@$?" #define SPECIAL_VARS "!#*@$?"
// bash specific
#define ARRAY_ARG_END " \t\n;#()&|<>]"
std::string import_file(std::string const& path); std::string import_file(std::string const& path);
shmain* parse_text(const char* in, uint32_t size, std::string const& filename=""); shmain* parse_text(const char* in, uint32_t size, std::string const& filename="");
@ -37,7 +41,7 @@ std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint3
std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word); std::pair<list*, uint32_t> parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word);
std::tuple<list*, uint32_t, std::string> parse_list_until(const char* in, uint32_t size, uint32_t start, std::vector<std::string> const& end_words, const char* expecting=NULL); std::tuple<list*, uint32_t, std::string> parse_list_until(const char* in, uint32_t size, uint32_t start, std::vector<std::string> const& end_words, const char* expecting=NULL);
// name // name
std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, uint32_t start, bool specialvars=true); std::pair<variable*, uint32_t> parse_var(const char* in, uint32_t size, uint32_t start, bool specialvars=true, bool array=false);
// subarg parsers // subarg parsers
std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size, uint32_t start); std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size, uint32_t start);

View file

@ -19,6 +19,12 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
// recursive calls // recursive calls
switch(o->type) switch(o->type)
{ {
case _obj::_variable :
{
variable* t = dynamic_cast<variable*>(o);
recurse(fct, t->index, args...);
break;
}
case _obj::_redirect : case _obj::_redirect :
{ {
redirect* t = dynamic_cast<redirect*>(o); redirect* t = dynamic_cast<redirect*>(o);
@ -115,7 +121,10 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
cmd* t = dynamic_cast<cmd*>(o); cmd* t = dynamic_cast<cmd*>(o);
recurse(fct, t->args, args...); recurse(fct, t->args, args...);
for(auto it: t->var_assigns) for(auto it: t->var_assigns)
{
recurse(fct, it.first, args...);
recurse(fct, it.second, args...); recurse(fct, it.second, args...);
}
for(auto it: t->redirs) for(auto it: t->redirs)
recurse(fct, it, args...); recurse(fct, it, args...);
@ -164,6 +173,8 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
case _obj::block_for : case _obj::block_for :
{ {
for_block* t = dynamic_cast<for_block*>(o); for_block* t = dynamic_cast<for_block*>(o);
// variable
recurse(fct, t->var, args...);
// iterations // iterations
recurse(fct, t->iter, args...); recurse(fct, t->iter, args...);
// for block // for block
@ -187,6 +198,12 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
break; break;
} }
case _obj::subarg_variable :
{
variable_subarg* t = dynamic_cast<variable_subarg*>(o);
recurse(fct, t->var, args...);
break;
}
case _obj::subarg_subshell : case _obj::subarg_subshell :
{ {
subshell_subarg* t = dynamic_cast<subshell_subarg*>(o); subshell_subarg* t = dynamic_cast<subshell_subarg*>(o);
@ -196,6 +213,7 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
case _obj::subarg_manipulation : case _obj::subarg_manipulation :
{ {
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(o); manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(o);
recurse(fct, t->var, args...);
recurse(fct, t->manip, args...); recurse(fct, t->manip, args...);
break; break;
} }
@ -211,6 +229,12 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
recurse(fct, t->arith, args...); recurse(fct, t->arith, args...);
break; break;
} }
case _obj::arithmetic_variable :
{
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(o);
recurse(fct, t->var, args...);
break;
}
case _obj::arithmetic_subshell : case _obj::arithmetic_subshell :
{ {
subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o); subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o);

View file

@ -84,6 +84,7 @@ class _obj
public: public:
enum _objtype { enum _objtype {
subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_manipulation, subarg_procsub, subarg_string, subarg_variable, subarg_subshell, subarg_arithmetic, subarg_manipulation, subarg_procsub,
_variable,
_redirect, _redirect,
_arg, arg_procsub, _arg, arg_procsub,
_arglist, _arglist,
@ -141,6 +142,21 @@ public:
std::string generate(int ind); std::string generate(int ind);
}; };
class variable : public _obj
{
public:
variable(std::string const& in="", arg* i=nullptr, bool def=false) { type=_obj::_variable; varname=in; index=i; definition=def; }
~variable() {
if(index!=nullptr) delete index;
}
std::string varname;
bool definition;
arg* index; // for bash specific
std::string generate(int ind);
};
// arglist // arglist
class arglist : public _obj class arglist : public _obj
@ -288,7 +304,7 @@ public:
// preceding var assigns // preceding var assigns
std::vector<std::pair<std::string,arg*>> var_assigns; std::vector<std::pair<variable*,arg*>> var_assigns;
// check if cmd is this (ex: unset) // check if cmd is this (ex: unset)
bool is(std::string const& in); bool is(std::string const& in);
@ -408,13 +424,14 @@ public:
class for_block : public block class for_block : public block
{ {
public: public:
for_block(std::string const& name="", arglist* args=nullptr, list* lst=nullptr) { type=_obj::block_for; varname=name; iter=args; ops=lst; } for_block(variable* in=nullptr, arglist* args=nullptr, list* lst=nullptr) { type=_obj::block_for; var=in; iter=args; ops=lst; }
~for_block() { ~for_block() {
if(iter!=nullptr) delete iter; if(iter!=nullptr) delete iter;
if(ops!=nullptr) delete ops; if(ops!=nullptr) delete ops;
if(var!=nullptr) delete var;
} }
std::string varname; variable* var;
arglist* iter; arglist* iter;
list* ops; list* ops;
@ -455,12 +472,14 @@ public:
class variable_subarg : public subarg class variable_subarg : public subarg
{ {
public: public:
variable_subarg(std::string const& in="", bool inq=false) { type=_obj::subarg_variable; varname=in; quoted=inq; } variable_subarg(variable* in=nullptr, bool inq=false) { type=_obj::subarg_variable; var=in; quoted=inq; }
~variable_subarg() {;} ~variable_subarg() {
if(var!=nullptr) delete var;
}
std::string varname; variable* var;
std::string generate(int ind) { return "$" + varname; } std::string generate(int ind) { return "$" + var->generate(ind); }
}; };
class arithmetic_subarg : public subarg class arithmetic_subarg : public subarg
@ -490,11 +509,14 @@ public:
class manipulation_subarg : public subarg class manipulation_subarg : public subarg
{ {
public: public:
manipulation_subarg(std::string varname="", arg* in=nullptr, bool inq=false) { type=_obj::subarg_manipulation; size=false; manip=in; quoted=inq; } manipulation_subarg(variable* vr=nullptr, arg* mn=nullptr, bool inq=false) { type=_obj::subarg_manipulation; size=false; var=vr; manip=mn; quoted=inq; }
~manipulation_subarg() { if(manip!=nullptr) delete manip; } ~manipulation_subarg() {
if(manip!=nullptr) delete manip;
if(var!=nullptr) delete var;
}
bool size; bool size;
std::string varname; variable* var;
arg* manip; arg* manip;
std::string generate(int ind); std::string generate(int ind);
@ -569,11 +591,14 @@ public:
class variable_arithmetic : public arithmetic class variable_arithmetic : public arithmetic
{ {
public: public:
variable_arithmetic(std::string const& in) { type=_obj::arithmetic_variable; varname=in; } variable_arithmetic(variable* in=nullptr) { type=_obj::arithmetic_variable; var=in; }
~variable_arithmetic() {
if(var!=nullptr) delete var;
}
std::string varname; variable* var;
std::string generate(int ind) { return varname; } std::string generate(int ind) { return var->generate(ind); }
}; };
#endif //STRUC_HPP #endif //STRUC_HPP

View file

@ -167,7 +167,7 @@ bool debashify_procsub(list* lst)
// replace the arg // replace the arg
delete affected_args[i].first->sa[0]; delete affected_args[i].first->sa[0];
affected_args[i].first->sa[0] = new string_subarg("\""); affected_args[i].first->sa[0] = new string_subarg("\"");
affected_args[i].first->add( new variable_subarg(strf("__lxshfifo%u", i)) ); affected_args[i].first->add( new variable_subarg( new variable(strf("__lxshfifo%u", i)) ) );
affected_args[i].first->add( new string_subarg("\"") ); affected_args[i].first->add( new string_subarg("\"") );
} }
lst->insert(li, *lst_insert ); lst->insert(li, *lst_insert );

View file

@ -177,7 +177,7 @@ std::string for_block::generate(int ind)
{ {
std::string ret; std::string ret;
ret += "for "+varname; ret += "for "+var->generate(ind);
if(iter != nullptr) if(iter != nullptr)
ret += " in " + iter->generate(ind); ret += " in " + iter->generate(ind);
ret += '\n'; ret += '\n';
@ -314,7 +314,7 @@ std::string cmd::generate(int ind)
std::string ret; std::string ret;
// var assigns // var assigns
for(auto it: var_assigns) for(auto it: var_assigns)
ret += it.first + '=' + it.second->generate(ind) + ' '; ret += it.first->generate(ind) + '=' + it.second->generate(ind) + ' ';
if(args!=nullptr && args->size()>0) if(args!=nullptr && args->size()>0)
{ {
@ -350,9 +350,9 @@ std::string subshell_subarg::generate(int ind)
std::string manipulation_subarg::generate(int ind) std::string manipulation_subarg::generate(int ind)
{ {
if(size) if(size)
return "${#" + varname + "}"; return "${#" + var->generate(ind) + "}";
else else
return "${" + varname + manip->generate(ind) + "}"; return "${" + var->generate(ind) + manip->generate(ind) + "}";
} }
std::string procsub_subarg::generate(int ind) std::string procsub_subarg::generate(int ind)
@ -412,6 +412,16 @@ std::string subshell_arithmetic::generate(int ind)
return '$' + sbsh->generate(ind); return '$' + sbsh->generate(ind);
} }
std::string variable::generate(int ind)
{
if(index!=nullptr)
{
return varname + '[' + index->generate(ind) + ']';
}
else
return varname;
}
// TEMPLATE // TEMPLATE
// std::string thing::generate(int ind) // std::string thing::generate(int ind)

View file

@ -56,49 +56,25 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::arithmetic_variable: { case _obj::_variable: {
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(in); variable* t = dynamic_cast<variable*>(in);
auto el=varmap->find(t->varname); auto el=varmap->find(t->varname);
if(el!=varmap->end()) if(el!=varmap->end())
t->varname = el->second; t->varname = el->second;
}; break; }; break;
case _obj::subarg_variable: {
variable_subarg* t = dynamic_cast<variable_subarg*>(in);
auto el=varmap->find(t->varname);
if(el!=varmap->end())
t->varname = el->second;
}; break;
case _obj::subarg_manipulation: {
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(in);
auto el=varmap->find(t->varname);
if(el!=varmap->end())
t->varname = el->second;
}; break;
case _obj::block_for: {
for_block* t = dynamic_cast<for_block*>(in);
auto it=varmap->find(t->varname);
if(it!=varmap->end())
t->varname = it->second;
}; break;
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd* t = dynamic_cast<cmd*>(in);
for(auto it=t->var_assigns.begin() ; it!=t->var_assigns.end() ; it++)
{
auto el=varmap->find(it->first);
if(el!=varmap->end())
it->first = el->second;
}
for(auto it: t->subarg_vars()) for(auto it: t->subarg_vars())
{ {
string_subarg* t = dynamic_cast<string_subarg*>(it); string_subarg* tss = dynamic_cast<string_subarg*>(it);
auto el=varmap->find(get_varname(t->val)); auto el=varmap->find(get_varname(tss->val));
if(el!=varmap->end()) if(el!=varmap->end())
{ {
size_t tpos=t->val.find('='); size_t tpos=tss->val.find('=');
if(tpos == std::string::npos) if(tpos == std::string::npos)
t->val = el->second; tss->val = el->second;
else else
t->val = el->second + t->val.substr(tpos); tss->val = el->second + tss->val.substr(tpos);
} }
} }
}; break; }; break;

View file

@ -127,22 +127,36 @@ uint32_t skip_unread(const char* in, uint32_t size, uint32_t start)
// parse fcts // parse fcts
std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, uint32_t start, bool specialvars) std::pair<variable*, uint32_t> parse_var(const char* in, uint32_t size, uint32_t start, bool specialvars, bool array)
{ {
uint32_t i=start; uint32_t i=start;
std::string ret; variable* ret=nullptr;
std::string varname;
// special vars // special vars
if(specialvars && (is_in(in[i], SPECIAL_VARS) || (in[i]>='0' && in[i]<='1')) ) if(specialvars && (is_in(in[i], SPECIAL_VARS) || (in[i]>='0' && in[i]<='1')) )
{ {
ret=in[i]; varname=in[i];
i++; i++;
} }
else // varname else // varname
{ {
while(i<size && (is_alphanum(in[i]) || in[i] == '_') ) while(i<size && (is_alphanum(in[i]) || in[i] == '_') )
i++; i++;
ret = std::string(in+start, i-start); varname = std::string(in+start, i-start);
}
if(varname != "")
{
ret = new variable(varname);
if(g_bash && array && in[i]=='[')
{
auto pp=parse_arg(in, size, i+1, ARRAY_ARG_END);
ret->index=pp.first;
i = pp.second;
if(in[i] != ']')
throw PARSE_ERROR( "Expecting ']'", i );
i++;
}
} }
return std::make_pair(ret, i); return std::make_pair(ret, i);
@ -186,6 +200,7 @@ std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size,
} }
else else
{ {
variable_arithmetic* ttvar=nullptr; // for categorizing definitions
if(in[i]=='-' || is_num(in[i])) if(in[i]=='-' || is_num(in[i]))
{ {
uint32_t j=i; uint32_t j=i;
@ -215,8 +230,9 @@ std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size,
specialvars=true; specialvars=true;
i++; i++;
} }
auto pp = parse_varname(in, size, i, specialvars); auto pp = parse_var(in, size, i, specialvars, true);
ret = new variable_arithmetic(pp.first); ttvar = new variable_arithmetic(pp.first);
ret = ttvar;
i=pp.second; i=pp.second;
} }
@ -234,6 +250,9 @@ std::pair<arithmetic*, uint32_t> parse_arithmetic(const char* in, uint32_t size,
i = skip_chars(in, size, i, SEPARATORS); i = skip_chars(in, size, i, SEPARATORS);
} }
if(po.first == "=" && ttvar!=nullptr) // categorize as var definition
ttvar->var->definition=true;
if(i >= size) if(i >= size)
throw PARSE_ERROR( "Unexpected end of file, expecting '))'", i ); throw PARSE_ERROR( "Unexpected end of file, expecting '))'", i );
if(in[i] != ')') if(in[i] != ')')
@ -262,10 +281,10 @@ std::pair<manipulation_subarg*, uint32_t> parse_manipulation(const char* in, uin
i++; i++;
} }
auto p=parse_varname(in, size, i); auto p=parse_var(in, size, i, true, true);
if(p.second == i) if(p.first == nullptr)
throw PARSE_ERROR( "Bad variable name", i ); throw PARSE_ERROR( "Bad variable name", i );
ret->varname=p.first; ret->var=p.first;
i = p.second; i = p.second;
auto pa = parse_arg(in, size, i, "}", NULL, false); auto pa = parse_arg(in, size, i, "}", NULL, false);
@ -357,14 +376,14 @@ std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t star
} }
else if( in[i] == '$' ) else if( in[i] == '$' )
{ {
auto r=parse_varname(in, size, i+1); auto r=parse_var(in, size, i+1);
if(r.second > i+1) if(r.first !=nullptr)
{ {
// add previous subarg // add previous subarg
std::string tmpstr=std::string(in+j, i-j); std::string tmpstr=std::string(in+j, i-j);
if(tmpstr!="") if(tmpstr!="")
ret->add(new string_subarg(tmpstr)); ret->add(new string_subarg(tmpstr));
// add varname // add var
ret->add(new variable_subarg(r.first, true)); ret->add(new variable_subarg(r.first, true));
j = i = r.second; j = i = r.second;
} }
@ -428,14 +447,14 @@ std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t star
} }
else if( in[i] == '$' ) else if( in[i] == '$' )
{ {
auto r=parse_varname(in, size, i+1); auto r=parse_var(in, size, i+1);
if(r.second > i+1) if(r.first != nullptr)
{ {
// add previous subarg // add previous subarg
std::string tmpstr=std::string(in+j, i-j); std::string tmpstr=std::string(in+j, i-j);
if(tmpstr!="") if(tmpstr!="")
ret->add(new string_subarg(tmpstr)); ret->add(new string_subarg(tmpstr));
// add varname // add var
ret->add(new variable_subarg(r.first)); ret->add(new variable_subarg(r.first));
j = i = r.second; j = i = r.second;
} }
@ -1061,10 +1080,11 @@ std::pair<cmd*, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t star
#endif #endif
while(true) // parse var assigns while(true) // parse var assigns
{ {
auto wp=get_word(in, size, i, VARNAME_END); auto vp=parse_var(in, size, i, false, true);
if(wp.second<size && in[wp.second] == '=' && valid_name(wp.first)) // is a var assign if(vp.first != nullptr && vp.second<size && in[vp.second] == '=') // is a var assign
{ {
i=wp.second+1; vp.first->definition=true;
i=vp.second+1;
arg* ta; arg* ta;
if( is_in(in[i], ARG_END) ) // no value : give empty value if( is_in(in[i], ARG_END) ) // no value : give empty value
{ {
@ -1076,11 +1096,15 @@ std::pair<cmd*, uint32_t> parse_cmd(const char* in, uint32_t size, uint32_t star
ta=pp.first; ta=pp.first;
i=pp.second; i=pp.second;
} }
ret->var_assigns.push_back(std::make_pair(wp.first, ta)); ret->var_assigns.push_back(std::make_pair(vp.first, ta));
i=skip_chars(in, size, i, " \t"); i=skip_chars(in, size, i, " \t");
} }
else else
{
if(vp.first != nullptr)
delete vp.first;
break; break;
}
} }
if(!is_in(in[i], SPECIAL_TOKENS)) if(!is_in(in[i], SPECIAL_TOKENS))
@ -1258,7 +1282,7 @@ std::pair<for_block*, uint32_t> parse_for(const char* in, uint32_t size, uint32_
if(!valid_name(wp.first)) if(!valid_name(wp.first))
throw PARSE_ERROR( strf("Bad identifier in for clause: '%s'", wp.first.c_str()), i ); throw PARSE_ERROR( strf("Bad identifier in for clause: '%s'", wp.first.c_str()), i );
ret->varname = wp.first; ret->var = new variable(wp.first, nullptr, true);
i=skip_chars(in, size, wp.second, SPACES); i=skip_chars(in, size, wp.second, SPACES);
// in // in
@ -1482,7 +1506,7 @@ shmain* parse_text(const char* in, uint32_t size, std::string const& filename)
i = skip_unread(in, size, i); i = skip_unread(in, size, i);
// do bash reading // do bash reading
std::string binshebang = basename(ret->shebang); std::string binshebang = basename(ret->shebang);
g_bash = binshebang == "bash" || binshebang == "lxsh" || options["debashify"]; g_bash = binshebang == "bash" || binshebang == "lxsh";
// parse all commands // parse all commands
auto pp=parse_list_until(in, size, i, 0); auto pp=parse_list_until(in, size, i, 0);
ret->lst=pp.first; ret->lst=pp.first;

View file

@ -263,31 +263,21 @@ bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
{ {
switch(in->type) switch(in->type)
{ {
case _obj::subarg_variable: { case _obj::_variable: {
variable_subarg* t = dynamic_cast<variable_subarg*>(in); variable* t = dynamic_cast<variable*>(in);
if(!callmap->insert( std::make_pair(t->varname, 1) ).second) if(t->definition)
(*callmap)[t->varname]++; {
}; break; if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
case _obj::arithmetic_variable: { (*defmap)[t->varname]++;
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(in); }
if(!callmap->insert( std::make_pair(t->varname, 1) ).second) else
(*callmap)[t->varname]++; {
}; break; if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
case _obj::subarg_manipulation: { (*callmap)[t->varname]++;
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(in); }
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
(*callmap)[t->varname]++;
}; break;
case _obj::block_for: {
for_block* t = dynamic_cast<for_block*>(in);
if(!defmap->insert( std::make_pair(t->varname, 1) ).second)
(*defmap)[t->varname]++;
}; break; }; break;
case _obj::block_cmd: { case _obj::block_cmd: {
cmd* t = dynamic_cast<cmd*>(in); cmd* t = dynamic_cast<cmd*>(in);
for(auto it: t->var_assigns)
if(!defmap->insert( std::make_pair(it.first, 1) ).second)
(*defmap)[it.first]++;
if(t->is_argvar()) if(t->is_argvar())
{ {
for(uint32_t i=1; i<t->args->size(); i++) for(uint32_t i=1; i<t->args->size(); i++)
@ -395,8 +385,9 @@ bool r_delete_var(_obj* in, set_t* vars)
for(uint32_t j=0; j<c->var_assigns.size(); j++) for(uint32_t j=0; j<c->var_assigns.size(); j++)
{ {
if( vars->find(c->var_assigns[j].first) != vars->end() ) if( vars->find(c->var_assigns[j].first->varname) != vars->end() )
{ {
delete c->var_assigns[j].first;
delete c->var_assigns[j].second; delete c->var_assigns[j].second;
c->var_assigns.erase(c->var_assigns.begin()+j); c->var_assigns.erase(c->var_assigns.begin()+j);
j--; j--;