implement arithmetic parsing and processing

This commit is contained in:
zawwz 2021-01-15 16:34:47 +01:00
parent 1b0c97f5bb
commit 7114a39fe3
10 changed files with 272 additions and 36 deletions

View file

@ -37,10 +37,10 @@ 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::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
std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, uint32_t start);
std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, uint32_t start, bool specialvars=true);
// subarg parsers
std::pair<arithmetic_subarg*, 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);
std::pair<manipulation_subarg*, uint32_t> parse_manipulation(const char* in, uint32_t size, uint32_t start);
// arg parser
std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t start, const char* end=ARG_END, const char* unexpected=SPECIAL_TOKENS, bool doquote=true);

View file

@ -205,6 +205,31 @@ void recurse(bool (&fct)(_obj*, Args...), _obj* o, Args... args)
recurse(fct, t->sbsh, args...);
break;
}
case _obj::subarg_arithmetic :
{
arithmetic_subarg* t = dynamic_cast<arithmetic_subarg*>(o);
recurse(fct, t->arith, args...);
break;
}
case _obj::arithmetic_subshell :
{
subshell_arithmetic* t = dynamic_cast<subshell_arithmetic*>(o);
recurse(fct, t->sbsh, args...);
break;
}
case _obj::arithmetic_operation :
{
operation_arithmetic* t = dynamic_cast<operation_arithmetic*>(o);
recurse(fct, t->val1, args...);
recurse(fct, t->val2, args...);
break;
}
case _obj::arithmetic_parenthesis :
{
parenthesis_arithmetic* t = dynamic_cast<parenthesis_arithmetic*>(o);
recurse(fct, t->val, args...);
break;
}
default: break; //do nothing
}

View file

@ -90,6 +90,7 @@ public:
_pipeline,
_condlist,
_list,
arithmetic_operation, arithmetic_number, arithmetic_variable, arithmetic_parenthesis, arithmetic_subshell,
block_subshell, block_brace, block_main, block_cmd, block_function, block_case, block_if, block_for, block_while, block_until };
_objtype type;
@ -97,6 +98,13 @@ public:
virtual std::string generate(int ind)=0;
};
// meta arithmetic type
class arithmetic : public _obj
{
public:
virtual std::string generate(int ind)=0;
};
// meta subarg type
class subarg : public _obj
{
@ -458,12 +466,14 @@ public:
class arithmetic_subarg : public subarg
{
public:
arithmetic_subarg() { type=_obj::subarg_arithmetic; }
~arithmetic_subarg() {;}
arithmetic_subarg(arithmetic* a=nullptr) { type=_obj::subarg_arithmetic; arith=a; }
~arithmetic_subarg() {
if(arith!=nullptr) delete arith;
}
std::string val;
arithmetic* arith;
std::string generate(int ind) { return "$(("+val+"))"; }
std::string generate(int ind);
};
class subshell_subarg : public subarg
@ -503,5 +513,67 @@ public:
std::string generate(int ind);
};
// Arithmetic subtypes //
class operation_arithmetic : public arithmetic
{
public:
operation_arithmetic(std::string op="", arithmetic* a=nullptr, arithmetic* b=nullptr, bool pre=false) { type=_obj::arithmetic_operation; oper=op; val1=a; val2=b; precedence=pre; }
~operation_arithmetic() {
if(val1 != nullptr) delete val1;
if(val2 != nullptr) delete val2;
}
std::string oper;
bool precedence;
arithmetic *val1, *val2;
std::string generate(int ind);
};
class subshell_arithmetic : public arithmetic
{
public:
subshell_arithmetic(subshell* a=nullptr) { type=_obj::arithmetic_subshell; sbsh=a; }
~subshell_arithmetic() {
if(sbsh!=nullptr) delete sbsh;
}
subshell* sbsh;
std::string generate(int ind);
};
class parenthesis_arithmetic : public arithmetic
{
public:
parenthesis_arithmetic(arithmetic* a=nullptr) { type=_obj::arithmetic_parenthesis; val=a; }
~parenthesis_arithmetic() {
if(val!=nullptr) delete val;
}
arithmetic* val;
std::string generate(int ind);
};
class number_arithmetic : public arithmetic
{
public:
number_arithmetic(std::string const& a) { type=_obj::arithmetic_number; val=a; }
std::string val;
std::string generate(int ind) { return val; }
};
class variable_arithmetic : public arithmetic
{
public:
variable_arithmetic(std::string const& in) { type=_obj::arithmetic_variable; varname=in; }
std::string varname;
std::string generate(int ind) { return varname; }
};
#endif //STRUC_HPP

View file

@ -23,6 +23,8 @@ std::string dirname(std::string const& in);
std::string indent(int n);
bool is_among(std::string const& in, std::vector<std::string> const& values);
std::vector<std::string> split(std::string const& in, const char* splitters);
std::vector<std::string> split(std::string const& in, char c);

View file

@ -96,22 +96,11 @@ bool debashify_extended_redirects(pipeline* in)
// replace <() and >()
/*
<() replacer:
REPLACE: CMD <(PSUB)
TO:
REPLACE TO:
fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10)
mkfifo "$fifoN"
( {PSUB;} > "$fifoN" ; rm "$fifoN") &
( {PSUB;} [>|<] "$fifoN" ; rm "$fifoN") &
CMD "$fifoN"
REPLACE CMD >(PSUB)
TO:
fifoN=${TMPDIR-/tmp}/lxshfifo_$(__lxsh_random 10)
mkfifo "$fifoN"
( {PSUB;} < "$fifoN" ; rm "$fifoN") &
jobN
CMD "$fifoN"
wait "$jobN"
*/
bool debashify_procsub(list* lst)
{

View file

@ -363,6 +363,55 @@ std::string procsub_subarg::generate(int ind)
return '<' + sbsh->generate(ind);
}
std::string arithmetic_subarg::generate(int ind)
{
std::string ret;
ret += "$((";
if(!opt_minimize) ret += ' ';
ret += arith->generate(ind);
if(!opt_minimize) ret += ' ';
ret += "))";
return ret;
}
// ARITHMETIC
std::string operation_arithmetic::generate(int ind)
{
std::string ret;
if(precedence)
{
ret += oper;
if(!opt_minimize) ret += ' ';
ret += val1->generate(ind);
}
else
{
ret += val1->generate(ind);
if(!opt_minimize) ret += ' ';
ret += oper;
if(!opt_minimize) ret += ' ';
ret += val2->generate(ind);
}
return ret;
}
std::string parenthesis_arithmetic::generate(int ind)
{
std::string ret;
ret += '(';
if(!opt_minimize) ret += ' ';
ret += val->generate(ind);
if(!opt_minimize) ret += ' ';
ret += ')';
return ret;
}
std::string subshell_arithmetic::generate(int ind)
{
return '$' + sbsh->generate(ind);
}
// TEMPLATE
// std::string thing::generate(int ind)

View file

@ -56,6 +56,12 @@ bool r_replace_var(_obj* in, strmap_t* varmap)
{
switch(in->type)
{
case _obj::arithmetic_variable: {
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(in);
auto el=varmap->find(t->varname);
if(el!=varmap->end())
t->varname = el->second;
}; break;
case _obj::subarg_variable: {
variable_subarg* t = dynamic_cast<variable_subarg*>(in);
auto el=varmap->find(t->varname);

View file

@ -18,6 +18,8 @@ bool g_bash=false;
#define PARSE_ERROR(str, i) ztd::format_error(str, "", in, i)
// constants
const std::vector<std::string> arithmetic_precedence_operators = { "!", "~", "+", "-" };
const std::vector<std::string> arithmetic_operators = { "+", "-", "*", "/", "=", "==", "!=", "&", "|", "^", "<<", ">>", "&&", "||" };
const std::vector<std::string> all_reserved_words = { "if", "then", "else", "fi", "case", "esac", "for", "while", "do", "done", "{", "}" };
const std::vector<std::string> out_reserved_words = { "then", "else", "fi", "esac", "do", "done", "}" };
@ -125,13 +127,13 @@ uint32_t skip_unread(const char* in, uint32_t size, uint32_t start)
// parse fcts
std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, uint32_t start)
std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, uint32_t start, bool specialvars)
{
uint32_t i=start;
std::string ret;
// special vars
if(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];
i++;
@ -146,28 +148,97 @@ std::pair<std::string, uint32_t> parse_varname(const char* in, uint32_t size, ui
return std::make_pair(ret, i);
}
std::pair<std::string, uint32_t> get_operator(const char* in, uint32_t size, uint32_t start)
{
uint32_t i=start;
std::string ret;
while(!is_alphanum(in[i]) && !is_in(in[i], SEPARATORS) && in[i]!=')' )
i++;
ret = std::string(in+start, i-start);
return std::make_pair(ret, i);
}
// parse an arithmetic
// ends at ))
// for now, uses subshell parsing then takes raw string value
// temporary, to improve
std::pair<arithmetic_subarg*, 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)
{
arithmetic_subarg* ret = new arithmetic_subarg;
arithmetic* ret = nullptr;
uint32_t i=start;
#ifndef NO_PARSE_CATCH
try
{
#endif
auto pp=parse_subshell(in, size, i);
i=pp.second;
delete pp.first;
if(i >= size || in[i]!=')')
i = skip_chars(in, size, i, SEPARATORS);
if(i>size || in[i] == ')')
throw PARSE_ERROR( "Unexpected end of arithmetic", i );
auto po = get_operator(in, size, i);
if(is_among(po.first, arithmetic_precedence_operators))
{
throw PARSE_ERROR( "Unexpected token ')', expecting '))'", i );
auto pa = parse_arithmetic(in, size, po.second);
ret = new operation_arithmetic(po.first, pa.first, nullptr, true);
i=pa.second;
}
else
{
if(in[i]=='-' || is_num(in[i]))
{
uint32_t j=i;
if(in[i]=='-')
i++;
while(is_num(in[i]))
i++;
ret = new number_arithmetic( std::string(in+j, i-j) );
}
else if(word_eq("$(", in, size, i))
{
auto ps = parse_subshell(in, size, i+2);
ret = new subshell_arithmetic(ps.first);
i=ps.second;
}
else if(in[i] == '(')
{
auto pa = parse_arithmetic(in, size, i+1);
ret = pa.first;
i = pa.second+1;
}
else
{
bool specialvars=false;
if(in[i] == '$')
{
specialvars=true;
i++;
}
auto pp = parse_varname(in, size, i, specialvars);
ret = new variable_arithmetic(pp.first);
i=pp.second;
}
i = skip_chars(in, size, i, SEPARATORS);
auto po = get_operator(in, size, i);
if(po.first != "")
{
if(!is_among(po.first, arithmetic_operators))
throw PARSE_ERROR( "Unknown arithmetic operator: "+po.first, i);
arithmetic* val1 = ret;
auto pa = parse_arithmetic(in, size, po.second);
arithmetic* val2 = pa.first;
i = pa.second;
ret = new operation_arithmetic(po.first, val1, val2);
i = skip_chars(in, size, i, SEPARATORS);
}
if(i >= size)
throw PARSE_ERROR( "Unexpected end of file, expecting '))'", i );
if(in[i] != ')')
throw PARSE_ERROR( "Unexpected token, expecting ')'", i);
}
ret->val = std::string(in+start, i-start-1);
i++;
#ifndef NO_PARSE_CATCH
}
catch(ztd::format_error& e)
@ -252,9 +323,14 @@ std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t star
ret->add(new string_subarg(tmpstr));
// get arithmetic
auto r=parse_arithmetic(in, size, i+3);
r.first->quoted=true;
ret->add(r.first);
j = i = r.second;
arithmetic_subarg* tt = new arithmetic_subarg(r.first);
tt->quoted=true;
ret->add(tt);
i = r.second;
if(!word_eq("))", in, size, i))
throw PARSE_ERROR( "Unexpected token ')', expecting '))'", i);
i+=2;
j=i;
}
else if( word_eq("$(", in, size, i) ) // substitution
{
@ -321,8 +397,12 @@ std::pair<arg*, uint32_t> parse_arg(const char* in, uint32_t size, uint32_t star
ret->add(new string_subarg(tmpstr));
// get arithmetic
auto r=parse_arithmetic(in, size, i+3);
ret->add(r.first);
j = i = r.second;
ret->add(new arithmetic_subarg(r.first));
i = r.second;
if(!word_eq("))", in, size, i))
throw PARSE_ERROR( "Unexpected token ')', expecting '))'", i);
i+=2;
j=i;
}
else if( word_eq("$(", in, size, i) ) // substitution
{

View file

@ -268,6 +268,11 @@ bool r_get_var(_obj* in, countmap_t* defmap, countmap_t* callmap)
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
(*callmap)[t->varname]++;
}; break;
case _obj::arithmetic_variable: {
variable_arithmetic* t = dynamic_cast<variable_arithmetic*>(in);
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)
(*callmap)[t->varname]++;
}; break;
case _obj::subarg_manipulation: {
manipulation_subarg* t = dynamic_cast<manipulation_subarg*>(in);
if(!callmap->insert( std::make_pair(t->varname, 1) ).second)

View file

@ -38,6 +38,14 @@ std::string dirname(std::string const& in)
return ".";
}
bool is_among(std::string const& in, std::vector<std::string> const& values)
{
for(auto it: values)
if(in == it)
return true;
return false;
}
std::vector<std::string> split(std::string const& in, const char* splitters)
{
uint32_t i=0,j=0;