diff --git a/include/parse.hpp b/include/parse.hpp index bd292bd..fc3b29f 100644 --- a/include/parse.hpp +++ b/include/parse.hpp @@ -37,10 +37,10 @@ std::pair parse_list_until(const char* in, uint32_t size, uint3 std::pair parse_list_until(const char* in, uint32_t size, uint32_t start, std::string const& end_word); std::tuple parse_list_until(const char* in, uint32_t size, uint32_t start, std::vector const& end_words, const char* expecting=NULL); // name -std::pair parse_varname(const char* in, uint32_t size, uint32_t start); +std::pair parse_varname(const char* in, uint32_t size, uint32_t start, bool specialvars=true); // subarg parsers -std::pair parse_arithmetic(const char* in, uint32_t size, uint32_t start); +std::pair parse_arithmetic(const char* in, uint32_t size, uint32_t start); std::pair parse_manipulation(const char* in, uint32_t size, uint32_t start); // arg parser std::pair parse_arg(const char* in, uint32_t size, uint32_t start, const char* end=ARG_END, const char* unexpected=SPECIAL_TOKENS, bool doquote=true); diff --git a/include/recursive.hpp b/include/recursive.hpp index 50912b5..a76139a 100644 --- a/include/recursive.hpp +++ b/include/recursive.hpp @@ -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(o); + recurse(fct, t->arith, args...); + break; + } + case _obj::arithmetic_subshell : + { + subshell_arithmetic* t = dynamic_cast(o); + recurse(fct, t->sbsh, args...); + break; + } + case _obj::arithmetic_operation : + { + operation_arithmetic* t = dynamic_cast(o); + recurse(fct, t->val1, args...); + recurse(fct, t->val2, args...); + break; + } + case _obj::arithmetic_parenthesis : + { + parenthesis_arithmetic* t = dynamic_cast(o); + recurse(fct, t->val, args...); + break; + } default: break; //do nothing } diff --git a/include/struc.hpp b/include/struc.hpp index 97bce64..2e7b761 100644 --- a/include/struc.hpp +++ b/include/struc.hpp @@ -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 diff --git a/include/util.hpp b/include/util.hpp index ec570e3..28e53c2 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -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 const& values); + std::vector split(std::string const& in, const char* splitters); std::vector split(std::string const& in, char c); diff --git a/src/debashify.cpp b/src/debashify.cpp index 9182166..a837ca3 100644 --- a/src/debashify.cpp +++ b/src/debashify.cpp @@ -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) { diff --git a/src/generate.cpp b/src/generate.cpp index aff450b..7ea9416 100644 --- a/src/generate.cpp +++ b/src/generate.cpp @@ -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) diff --git a/src/minimize.cpp b/src/minimize.cpp index 9ec348c..2c064c0 100644 --- a/src/minimize.cpp +++ b/src/minimize.cpp @@ -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(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(in); auto el=varmap->find(t->varname); diff --git a/src/parse.cpp b/src/parse.cpp index 4f301f8..731642a 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -18,6 +18,8 @@ bool g_bash=false; #define PARSE_ERROR(str, i) ztd::format_error(str, "", in, i) // constants +const std::vector arithmetic_precedence_operators = { "!", "~", "+", "-" }; +const std::vector arithmetic_operators = { "+", "-", "*", "/", "=", "==", "!=", "&", "|", "^", "<<", ">>", "&&", "||" }; const std::vector all_reserved_words = { "if", "then", "else", "fi", "case", "esac", "for", "while", "do", "done", "{", "}" }; const std::vector 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 parse_varname(const char* in, uint32_t size, uint32_t start) +std::pair 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 parse_varname(const char* in, uint32_t size, ui return std::make_pair(ret, i); } +std::pair 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 parse_arithmetic(const char* in, uint32_t size, uint32_t start) +std::pair 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 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 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 { diff --git a/src/processing.cpp b/src/processing.cpp index cfd0e8b..dc244bf 100644 --- a/src/processing.cpp +++ b/src/processing.cpp @@ -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(in); + if(!callmap->insert( std::make_pair(t->varname, 1) ).second) + (*callmap)[t->varname]++; + }; break; case _obj::subarg_manipulation: { manipulation_subarg* t = dynamic_cast(in); if(!callmap->insert( std::make_pair(t->varname, 1) ).second) diff --git a/src/util.cpp b/src/util.cpp index eedc38d..e0bc7ff 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -38,6 +38,14 @@ std::string dirname(std::string const& in) return "."; } +bool is_among(std::string const& in, std::vector const& values) +{ + for(auto it: values) + if(in == it) + return true; + return false; +} + std::vector split(std::string const& in, const char* splitters) { uint32_t i=0,j=0;