implement arithmetic parsing and processing
This commit is contained in:
parent
1b0c97f5bb
commit
7114a39fe3
10 changed files with 272 additions and 36 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
114
src/parse.cpp
114
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<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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue