Major rework
+ Move to pointers internally (performance improvement) + Polymorphic internal classes (performance improvement) + Add if/for/while parsing
This commit is contained in:
parent
fd19eab3db
commit
6350e1cfef
7 changed files with 1457 additions and 593 deletions
|
|
@ -11,7 +11,7 @@ extern std::string g_origin;
|
|||
|
||||
std::string import_file(std::string const& path);
|
||||
|
||||
block parse(const char* in, uint32_t size);
|
||||
inline block parse(std::string const& in) { return parse(in.c_str(), in.size()); }
|
||||
shmain* parse(const char* in, uint32_t size);
|
||||
inline shmain* parse(std::string const& in) { return parse(in.c_str(), in.size()); }
|
||||
|
||||
#endif //PARSE_HPP
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
|
@ -12,18 +11,37 @@
|
|||
structure:
|
||||
|
||||
list_t : condlist[]
|
||||
arglist_t : arg[]
|
||||
|
||||
block:
|
||||
- group
|
||||
- brace: list_t
|
||||
- subsh: list_t
|
||||
- cmd: arglist[]
|
||||
block: can be one of
|
||||
- main
|
||||
string (shebang)
|
||||
list_t (commands)
|
||||
- brace
|
||||
list_t
|
||||
- subshell
|
||||
list_t
|
||||
- cmd: arglist
|
||||
- case
|
||||
- arg (input)
|
||||
- pair<arg,list_t>[] (cases)
|
||||
arg (input)
|
||||
pair<arglist_t,list_t>[] (cases)
|
||||
- if
|
||||
pair<list_t,list_t>[] (blocks)
|
||||
list_t (else)
|
||||
- for
|
||||
string (variable name)
|
||||
arglist (iterations)
|
||||
list_t (execution)
|
||||
- while
|
||||
list_t (condition)
|
||||
list_t (execution)
|
||||
|
||||
|
||||
condlist:
|
||||
pipeline[]
|
||||
or_ops[]
|
||||
> always one smaller than pipeline
|
||||
> designates an OR if true, otherwise an AND
|
||||
|
||||
pipeline:
|
||||
block[]
|
||||
|
|
@ -31,13 +49,15 @@ pipeline:
|
|||
arglist:
|
||||
arg[]
|
||||
|
||||
arg:
|
||||
- raw
|
||||
- subarg[] split into subarguments in case of subshells
|
||||
arg: has
|
||||
raw
|
||||
subarg[] can have multiple subarguments if string and subshells
|
||||
|
||||
subarg:
|
||||
- raw
|
||||
subarg: can be one of
|
||||
- string
|
||||
- block: subshell (substitution)
|
||||
- arithmetic
|
||||
|
||||
*/
|
||||
|
||||
#define AND_OP false
|
||||
|
|
@ -48,26 +68,42 @@ class block;
|
|||
class pipeline;
|
||||
class arg;
|
||||
class subarg;
|
||||
class cmd;
|
||||
|
||||
// type pack of condlist
|
||||
typedef std::vector<condlist> list_t;
|
||||
typedef std::vector<condlist*> list_t;
|
||||
typedef std::vector<arg*> arglist_t;
|
||||
|
||||
block make_cmd(std::vector<std::string> args);
|
||||
cmd* make_cmd(std::vector<std::string> args);
|
||||
|
||||
bool add_include(std::string const& file);
|
||||
|
||||
// meta subarg type
|
||||
class subarg
|
||||
{
|
||||
public:
|
||||
// type
|
||||
enum argtype { s_string, s_subshell, s_arithmetic };
|
||||
argtype type;
|
||||
|
||||
virtual ~subarg() {;}
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class arg
|
||||
{
|
||||
public:
|
||||
arg() { ; }
|
||||
arg(std::string const& str) {this->setstring(str);}
|
||||
~arg() { for(auto it: sa) delete it; }
|
||||
|
||||
void setstring(std::string const& str);
|
||||
|
||||
// has to be set manually
|
||||
std::string raw;
|
||||
|
||||
std::vector<subarg> sa;
|
||||
std::vector<subarg*> sa;
|
||||
|
||||
// return if is a string and only one subarg
|
||||
std::string string();
|
||||
|
|
@ -75,111 +111,283 @@ public:
|
|||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
// arglist
|
||||
|
||||
class arglist
|
||||
{
|
||||
public:
|
||||
inline void add(arg const& in) { args.push_back(in); }
|
||||
inline void push_back(arg const& in) { args.push_back(in); }
|
||||
~arglist() { for( auto it: args ) delete it; }
|
||||
inline void add(arg* in) { args.push_back(in); }
|
||||
inline void push_back(arg* in) { args.push_back(in); }
|
||||
|
||||
std::vector<arg> args;
|
||||
arglist_t args;
|
||||
|
||||
std::vector<std::string> strargs(uint32_t start);
|
||||
|
||||
inline uint64_t size() { return args.size(); }
|
||||
inline arg& operator[](uint32_t i) { return args[i]; }
|
||||
inline arg* operator[](uint32_t i) { return args[i]; }
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class redir
|
||||
{
|
||||
public:
|
||||
enum redirtype { none, write, append, read, raw } ;
|
||||
redir(redirtype in=none) { type=in; }
|
||||
redirtype type;
|
||||
arg val;
|
||||
};
|
||||
|
||||
class block
|
||||
{
|
||||
public:
|
||||
// type
|
||||
enum blocktype { none, subshell, brace, main, cmd, function, case_block, for_block, if_block, while_block};
|
||||
blocktype type;
|
||||
|
||||
// ctor
|
||||
block() { type=none; }
|
||||
block(blocktype in) { type=in; }
|
||||
|
||||
// subshell/brace/main
|
||||
list_t cls;
|
||||
|
||||
// cmd
|
||||
arglist args;
|
||||
|
||||
// case
|
||||
arg carg;
|
||||
std::vector< std::pair<std::vector<arg>, list_t> > cases;
|
||||
|
||||
// main: shebang
|
||||
// function: name
|
||||
std::string shebang;
|
||||
|
||||
// subshell: return the containing cmd, if it is a single command
|
||||
block* single_cmd();
|
||||
|
||||
std::string generate(int ind=0, bool print_shebang=true);
|
||||
|
||||
private:
|
||||
std::string generate_cmd(int ind);
|
||||
std::string generate_case(int ind);
|
||||
};
|
||||
// PL
|
||||
|
||||
class pipeline
|
||||
{
|
||||
public:
|
||||
pipeline() {;}
|
||||
pipeline(block const& bl) { cmds.push_back(bl); }
|
||||
inline void add(block bl) { this->cmds.push_back(bl); }
|
||||
std::vector<block> cmds;
|
||||
pipeline() { negated=false; }
|
||||
pipeline(block* bl) { cmds.push_back(bl); negated=false; }
|
||||
inline void add(block* bl) { this->cmds.push_back(bl); }
|
||||
std::vector<block*> cmds;
|
||||
|
||||
bool negated; // negated return value (! at start)
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
// CL
|
||||
|
||||
class condlist
|
||||
{
|
||||
public:
|
||||
condlist() { parallel=false; }
|
||||
condlist(block const& pl) { parallel=false; this->add(pl);}
|
||||
condlist(pipeline const& pl) { parallel=false; this->add(pl);}
|
||||
condlist(pipeline const& pl) { parallel=false; this->add(new pipeline(pl));}
|
||||
condlist(pipeline* pl) { parallel=false; this->add(pl);}
|
||||
|
||||
bool parallel; // & at the end
|
||||
|
||||
void add(pipeline const& pl, bool or_op=false);
|
||||
void add(pipeline* pl, bool or_op=false);
|
||||
// don't push_back here, use add() instead
|
||||
std::vector<pipeline> pls;
|
||||
std::vector<pipeline*> pls;
|
||||
std::vector<bool> or_ops; // size of 1 less than pls, defines separator between pipelines
|
||||
|
||||
void negate();
|
||||
|
||||
std::string generate(int ind, bool pre_indent=true);
|
||||
};
|
||||
|
||||
// class redir
|
||||
// {
|
||||
// public:
|
||||
// enum redirtype { none, write, append, read, raw } ;
|
||||
// redir(redirtype in=none) { type=in; }
|
||||
// redirtype type;
|
||||
// arg val;
|
||||
// };
|
||||
|
||||
|
||||
class cmd;
|
||||
|
||||
// Meta block
|
||||
class block
|
||||
{
|
||||
public:
|
||||
// type
|
||||
enum blocktype { block_subshell, block_brace, block_main, block_cmd, block_function, block_case, block_if, block_for, block_while, block_until };
|
||||
blocktype type;
|
||||
|
||||
// ctor
|
||||
block() { redirs=nullptr; }
|
||||
virtual ~block() { if(redirs!=nullptr) delete redirs; }
|
||||
|
||||
// cmd
|
||||
arglist* redirs;
|
||||
|
||||
// subshell: return the containing cmd, if it is a single command
|
||||
cmd* single_cmd();
|
||||
|
||||
std::string generate_redirs(int ind);
|
||||
|
||||
virtual std::string generate(int ind)=0;
|
||||
};
|
||||
|
||||
// block types
|
||||
|
||||
class subshell : public block
|
||||
{
|
||||
public:
|
||||
subshell() { type=block::block_subshell; }
|
||||
~subshell() { for(auto it: cls) delete it; }
|
||||
|
||||
cmd* single_cmd();
|
||||
|
||||
list_t cls;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
class brace : public block
|
||||
{
|
||||
public:
|
||||
brace() { type=block::block_brace; }
|
||||
~brace() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
for(auto it: cls) delete it; }
|
||||
|
||||
cmd* single_cmd();
|
||||
|
||||
list_t cls;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
|
||||
class subarg
|
||||
class shmain : public block
|
||||
{
|
||||
public:
|
||||
// type
|
||||
enum argtype { string, subshell, arithmetic };
|
||||
argtype type;
|
||||
shmain() { type=block::block_main; }
|
||||
~shmain() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
for(auto it: cls) delete it; }
|
||||
|
||||
// ctor
|
||||
subarg(argtype in) { this->type=in; }
|
||||
subarg(std::string const& in="") { type=string; val=in; }
|
||||
subarg(block const& in) { type=subshell; sbsh=in; }
|
||||
std::string shebang;
|
||||
list_t cls;
|
||||
|
||||
std::string generate(bool print_shebang=true, int ind=0);
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class function : public block
|
||||
{
|
||||
public:
|
||||
function() { type=block::block_function; }
|
||||
~function() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
for(auto it: cls) delete it; }
|
||||
|
||||
std::string name;
|
||||
list_t cls;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class cmd : public block
|
||||
{
|
||||
public:
|
||||
cmd(arglist* in=nullptr) { type=block::block_cmd; args=in; }
|
||||
~cmd() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
if(args!=nullptr) delete args; }
|
||||
|
||||
static const std::string empty_string;
|
||||
|
||||
std::string const& firstarg_raw();
|
||||
|
||||
arglist* args;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class case_block : public block
|
||||
{
|
||||
public:
|
||||
case_block(arg* in=nullptr) { type=block::block_case; carg=in; }
|
||||
~case_block() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
if(carg!=nullptr) delete carg;
|
||||
for( auto cit : cases )
|
||||
{
|
||||
for( auto ait : cit.first )
|
||||
delete ait;
|
||||
for( auto lit : cit.second )
|
||||
delete lit;
|
||||
}
|
||||
}
|
||||
|
||||
arg* carg;
|
||||
std::vector< std::pair<arglist_t, list_t> > cases;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class if_block : public block
|
||||
{
|
||||
public:
|
||||
if_block() { type=block::block_if; }
|
||||
~if_block() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
for(auto it: else_cls) delete it;
|
||||
for(auto ifb: blocks)
|
||||
{
|
||||
for(auto it: ifb.first)
|
||||
delete it;
|
||||
for(auto it: ifb.second)
|
||||
delete it;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector< std::pair<list_t,list_t> > blocks;
|
||||
|
||||
list_t else_cls;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class for_block : public block
|
||||
{
|
||||
public:
|
||||
for_block(std::string const& name="", arglist* args=nullptr) { type=block::block_for; varname=name; iter=args; }
|
||||
~for_block() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
if(iter!=nullptr) delete iter;
|
||||
for(auto it: ops) delete it;
|
||||
}
|
||||
|
||||
std::string varname;
|
||||
|
||||
arglist* iter;
|
||||
list_t ops;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
class while_block : public block
|
||||
{
|
||||
public:
|
||||
while_block() { type=block::block_while; }
|
||||
~while_block() {
|
||||
if(redirs!=nullptr) delete redirs;
|
||||
for(auto it: cond) delete it;
|
||||
for(auto it: ops) delete it;
|
||||
}
|
||||
|
||||
condlist* real_condition() { return *(cond.end()-1); }
|
||||
|
||||
list_t cond;
|
||||
list_t ops;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
||||
// Subarg subtypes
|
||||
|
||||
class subarg_string : public subarg
|
||||
{
|
||||
public:
|
||||
subarg_string(std::string const& in="") { type=subarg::s_string; val=in; }
|
||||
|
||||
// raw string
|
||||
std::string val;
|
||||
// subshell
|
||||
block sbsh;
|
||||
|
||||
std::string generate(int ind) { return val; }
|
||||
};
|
||||
|
||||
class subarg_arithmetic : public subarg
|
||||
{
|
||||
public:
|
||||
subarg_arithmetic() { type=subarg::s_arithmetic; }
|
||||
|
||||
std::string val;
|
||||
|
||||
std::string generate(int ind) { return "$(("+val+"))"; }
|
||||
};
|
||||
|
||||
class subarg_subshell : public subarg
|
||||
{
|
||||
public:
|
||||
subarg_subshell(subshell* in=nullptr) { type=subarg::s_subshell; sbsh=in; }
|
||||
subarg_subshell(subshell in) { type=subarg::s_subshell; sbsh=new subshell(in); }
|
||||
~subarg_subshell() { if(sbsh != nullptr) delete sbsh;}
|
||||
|
||||
subshell* sbsh;
|
||||
|
||||
std::string generate(int ind);
|
||||
};
|
||||
|
|
|
|||
410
src/generate.cpp
410
src/generate.cpp
|
|
@ -15,12 +15,20 @@ bool is_sub_special_cmd(std::string in)
|
|||
return in == "%include_sub" || in == "%resolve_sub";
|
||||
}
|
||||
|
||||
std::string indented(std::string const& in, uint32_t ind)
|
||||
{
|
||||
if(!opt_minimize)
|
||||
return indent(ind) + in;
|
||||
else
|
||||
return in;
|
||||
}
|
||||
|
||||
std::string arg::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
for(auto it: sa)
|
||||
{
|
||||
ret += it.generate(ind);
|
||||
ret += it->generate(ind);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -31,7 +39,7 @@ std::string arglist::generate(int ind)
|
|||
|
||||
for(auto it: args)
|
||||
{
|
||||
ret += it.generate(ind);
|
||||
ret += it->generate(ind);
|
||||
ret += ' ';
|
||||
}
|
||||
|
||||
|
|
@ -47,31 +55,33 @@ std::string pipeline::generate(int ind)
|
|||
if(cmds.size()<=0)
|
||||
return "";
|
||||
|
||||
ret += cmds[0].generate(ind);
|
||||
if(negated)
|
||||
ret += "! ";
|
||||
ret += cmds[0]->generate(ind);
|
||||
for(uint32_t i=1 ; i<cmds.size() ; i++)
|
||||
{
|
||||
ret += opt_minimize ? "|" : " | " ;
|
||||
ret += cmds[i].generate(ind);
|
||||
ret += cmds[i]->generate(ind);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string condlist::generate(int ind)
|
||||
std::string condlist::generate(int ind, bool pre_indent)
|
||||
{
|
||||
std::string ret;
|
||||
if(pls.size() <= 0)
|
||||
return "";
|
||||
if(!opt_minimize)
|
||||
ret += INDENT;
|
||||
ret += pls[0].generate(ind);
|
||||
if(pre_indent)
|
||||
ret += indented("", ind);
|
||||
ret += pls[0]->generate(ind);
|
||||
for(uint32_t i=0 ; i<pls.size()-1 ; i++)
|
||||
{
|
||||
if(or_ops[i])
|
||||
ret += opt_minimize ? "||" : " || ";
|
||||
else
|
||||
ret += opt_minimize ? "&&" : " && ";
|
||||
ret += pls[i+1].generate(ind);
|
||||
ret += pls[i+1]->generate(ind);
|
||||
}
|
||||
if(ret=="")
|
||||
return "";
|
||||
|
|
@ -136,18 +146,18 @@ std::string generate_resolve(std::vector<std::string> args, int ind)
|
|||
|
||||
if(opts['p'])
|
||||
{
|
||||
block bl;
|
||||
shmain* sh;
|
||||
try
|
||||
{
|
||||
bl = parse(p.first);
|
||||
sh = parse(p.first);
|
||||
}
|
||||
catch(ztd::format_error& e)
|
||||
{
|
||||
throw ztd::format_error(e.what(), "command `"+cmd+'`', e.data(), e.where());
|
||||
}
|
||||
ret = bl.generate(ind, false);
|
||||
std::string tmpind=INDENT;
|
||||
ret = ret.substr(tmpind.size());
|
||||
ret = sh->generate(false, ind);
|
||||
delete sh;
|
||||
ret = ret.substr(indent(ind).size());
|
||||
ret.pop_back(); // remove \n
|
||||
}
|
||||
else
|
||||
|
|
@ -198,7 +208,7 @@ std::string generate_include(std::vector<std::string> args, int ind)
|
|||
|
||||
|
||||
std::string file;
|
||||
block bl;
|
||||
shmain* bl=nullptr;
|
||||
bool indent_remove=true;
|
||||
|
||||
for(auto it : v)
|
||||
|
|
@ -224,12 +234,12 @@ std::string generate_include(std::vector<std::string> args, int ind)
|
|||
{
|
||||
throw ztd::format_error(e.what(), it, e.data(), e.where());
|
||||
}
|
||||
file = bl.generate(ind, false);
|
||||
file = bl->generate(false, ind);
|
||||
delete bl;
|
||||
if(indent_remove)
|
||||
{
|
||||
indent_remove=false;
|
||||
std::string tmpind=INDENT;
|
||||
file = file.substr(tmpind.size());
|
||||
file = file.substr(indent(ind).size());
|
||||
}
|
||||
ret += file;
|
||||
}
|
||||
|
|
@ -246,161 +256,253 @@ std::string generate_include(std::vector<std::string> args, int ind)
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::string block::generate_cmd(int ind)
|
||||
// BLOCK
|
||||
|
||||
std::string block::generate_redirs(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
if(args.size()<=0)
|
||||
return "";
|
||||
std::string cmd=args[0].raw;
|
||||
if(cmd == "%include" || cmd == "%include_s")
|
||||
if(redirs != nullptr)
|
||||
{
|
||||
ret += generate_include(args.strargs(1), ind);
|
||||
}
|
||||
else if(cmd == "%resolve" || cmd == "%resolve_s")
|
||||
{
|
||||
ret += generate_resolve(args.strargs(1), ind);
|
||||
}
|
||||
else
|
||||
ret = args.generate(ind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string block::generate_case(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
ret += "case " + carg.generate(ind) + " in\n";
|
||||
ind++;
|
||||
for(auto cs: this->cases)
|
||||
{
|
||||
// case definition : foo)
|
||||
if(!opt_minimize) ret += INDENT;
|
||||
for(auto it: cs.first)
|
||||
ret += it.generate(ind) + '|';
|
||||
ret.pop_back();
|
||||
ret += ')';
|
||||
if(!opt_minimize) ret += '\n';
|
||||
// commands
|
||||
for(auto it: cs.second)
|
||||
ret += it.generate(ind+1);
|
||||
// end of case: ;;
|
||||
if(opt_minimize)
|
||||
{
|
||||
// ;; can be right after command
|
||||
if(ret[ret.size()-1] == '\n')
|
||||
ret.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
ind++;
|
||||
ret += INDENT;
|
||||
ind--;
|
||||
}
|
||||
ret += ";;\n";
|
||||
}
|
||||
// close case
|
||||
ind--;
|
||||
if(!opt_minimize) ret += INDENT;
|
||||
ret += "esac";
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string block::generate(int ind, bool print_shebang)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
if(type==cmd)
|
||||
{
|
||||
ret += generate_cmd(ind);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(type==function)
|
||||
{
|
||||
// function definition
|
||||
ret += shebang + "()";
|
||||
if(!opt_minimize) ret += '\n' + INDENT;
|
||||
ret += "{\n";
|
||||
// commands
|
||||
for(auto it: cls)
|
||||
ret += it.generate(ind+1);
|
||||
if(!opt_minimize) ret += INDENT;
|
||||
// end function
|
||||
ret += '}';
|
||||
}
|
||||
else if(type==subshell)
|
||||
{
|
||||
// open subshell
|
||||
ret += '(';
|
||||
if(!opt_minimize) ret += '\n';
|
||||
// commands
|
||||
for(auto it: cls)
|
||||
ret += it.generate(ind+1);
|
||||
if(opt_minimize && ret.size()>1)
|
||||
ret.pop_back(); // ) can be right after command
|
||||
else
|
||||
ret += INDENT;
|
||||
// close subshell
|
||||
ret += ')';
|
||||
}
|
||||
else if(type==brace)
|
||||
{
|
||||
ret += "{\n" ;
|
||||
for(auto it: cls)
|
||||
ret += it.generate(ind+1);
|
||||
if(!opt_minimize)
|
||||
ret += INDENT;
|
||||
ret += '}';
|
||||
}
|
||||
else if(type==main)
|
||||
{
|
||||
if(print_shebang && shebang!="")
|
||||
ret += shebang + '\n';
|
||||
for(auto it: cls)
|
||||
ret += it.generate(ind);
|
||||
}
|
||||
else if(type==case_block)
|
||||
{
|
||||
ret += generate_case(ind);
|
||||
}
|
||||
|
||||
std::string t = generate_cmd(ind); // leftover redirections
|
||||
std::string t = redirs->generate(ind);
|
||||
if(t!="")
|
||||
{
|
||||
if(!opt_minimize) ret += ' ';
|
||||
ret += t;
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string if_block::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
for(uint32_t i=0; i<blocks.size(); i++ )
|
||||
{
|
||||
// condition
|
||||
if(i==0)
|
||||
ret += "if ";
|
||||
else
|
||||
ret += "elif ";
|
||||
// first cmd: on same line with no indent
|
||||
ret += blocks[i].first[0]->generate(ind+1, false);
|
||||
// other cmds: on new lines
|
||||
for(uint32_t j=1; j<blocks[i].first.size(); j++ )
|
||||
ret += blocks[i].first[j]->generate(ind+1);
|
||||
|
||||
// execution
|
||||
ret += indented("then\n", ind);
|
||||
for(auto it: blocks[i].second)
|
||||
ret += it->generate(ind+1);
|
||||
}
|
||||
|
||||
if(else_cls.size()>0)
|
||||
{
|
||||
ret += indented("else\n", ind);
|
||||
for(auto it: else_cls)
|
||||
ret += it->generate(ind+1);
|
||||
}
|
||||
|
||||
ret += indented("fi", ind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string for_block::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
ret += "for "+varname;
|
||||
if(iter != nullptr)
|
||||
ret += " in " + iter->generate(ind);
|
||||
ret += '\n';
|
||||
ret += indented("do\n", ind);
|
||||
for(auto it: ops)
|
||||
ret += it->generate(ind+1);
|
||||
ret += indented("done", ind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string while_block::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
ret += "while";
|
||||
if(cond.size() == 1)
|
||||
{
|
||||
ret += " " + cond[0]->generate(ind+1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += '\n';
|
||||
for(auto it: cond)
|
||||
ret += it->generate(ind+1);
|
||||
}
|
||||
ret += indented("do\n", ind);
|
||||
for(auto it: ops)
|
||||
ret += it->generate(ind+1);
|
||||
ret += indented("done", ind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string subshell::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
// open subshell
|
||||
ret += '(';
|
||||
if(!opt_minimize) ret += '\n';
|
||||
// commands
|
||||
for(auto it: cls)
|
||||
ret += it->generate(ind+1);
|
||||
if(opt_minimize && ret.size()>1)
|
||||
ret.pop_back(); // ) can be right after command
|
||||
// close subshell
|
||||
ret += indented(")", ind);
|
||||
|
||||
ret += generate_redirs(ind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string shmain::generate(int ind)
|
||||
{
|
||||
return this->generate(false, ind);
|
||||
}
|
||||
std::string shmain::generate(bool print_shebang, int ind)
|
||||
{
|
||||
std::string ret;
|
||||
if(print_shebang && shebang!="")
|
||||
ret += shebang + '\n';
|
||||
for(auto it: cls)
|
||||
ret += it->generate(ind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string brace::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
ret += "{\n" ;
|
||||
for(auto it: cls)
|
||||
ret += it->generate(ind+1);
|
||||
|
||||
ret += indented("}", ind);
|
||||
|
||||
ret += generate_redirs(ind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string function::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
// function definition
|
||||
ret += name + "()";
|
||||
if(!opt_minimize) ret += '\n' + indent(ind);
|
||||
ret += "{\n";
|
||||
// commands
|
||||
for(auto it: cls)
|
||||
ret += it->generate(ind+1);
|
||||
ret += indented("}", ind);
|
||||
|
||||
ret += generate_redirs(ind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string case_block::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
ret += "case " + carg->generate(ind) + " in\n";
|
||||
ind++;
|
||||
for(auto cs: this->cases)
|
||||
{
|
||||
// case definition : foo)
|
||||
ret += indented("", ind);
|
||||
// args
|
||||
for(auto it: cs.first)
|
||||
ret += it->generate(ind) + '|';
|
||||
ret.pop_back();
|
||||
ret += ')';
|
||||
if(!opt_minimize) ret += '\n';
|
||||
// commands
|
||||
for(auto it: cs.second)
|
||||
ret += it->generate(ind+1);
|
||||
// end of case: ;;
|
||||
if(opt_minimize && ret[ret.size()-1] == '\n') // ;; can be right after command
|
||||
{
|
||||
ret.pop_back();
|
||||
}
|
||||
ret += indented(";;\n", ind+1);
|
||||
}
|
||||
// close case
|
||||
ind--;
|
||||
ret += indented("esac", ind);
|
||||
|
||||
ret += generate_redirs(ind);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string cmd::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
if(args==nullptr || args->size()<=0)
|
||||
return "";
|
||||
std::string cmdname=(*args)[0]->raw;
|
||||
if(cmdname == "%include" || cmdname == "%include_s")
|
||||
{
|
||||
ret += generate_include(args->strargs(1), ind);
|
||||
}
|
||||
else if(cmdname == "%resolve" || cmdname == "%resolve_s")
|
||||
{
|
||||
ret += generate_resolve(args->strargs(1), ind);
|
||||
}
|
||||
else
|
||||
ret = args->generate(ind);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TEMPLATE
|
||||
|
||||
// std::string thing::generate(int ind)
|
||||
// {
|
||||
// std::string ret;
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
// SUBARG
|
||||
|
||||
std::string subarg::generate(int ind)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case subarg::s_string:
|
||||
return dynamic_cast<subarg_string*>(this)->generate(ind);
|
||||
case subarg::s_arithmetic:
|
||||
return dynamic_cast<subarg_arithmetic*>(this)->generate(ind);
|
||||
case subarg::s_subshell:
|
||||
return dynamic_cast<subarg_subshell*>(this)->generate(ind);
|
||||
}
|
||||
// doesn't happen, just to get rid of warning
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string subarg_subshell::generate(int ind)
|
||||
{
|
||||
std::string ret;
|
||||
if(type == subarg::string)
|
||||
// includes and resolves inside command substitutions
|
||||
// resolve here and not inside subshell
|
||||
cmd* cmd = sbsh->single_cmd();
|
||||
if( cmd != nullptr && (cmd->firstarg_raw() == "%include" || cmd->firstarg_raw() == "%resolve") )
|
||||
{
|
||||
ret += val;
|
||||
ret += cmd->generate(ind);
|
||||
}
|
||||
else if(type == subarg::arithmetic)
|
||||
// regular substitution
|
||||
else
|
||||
{
|
||||
ret += "$(("+val+"))";
|
||||
}
|
||||
else if(type == subarg::subshell)
|
||||
{
|
||||
// includes and resolves inside command substitutions
|
||||
// resolve here and not inside subshell
|
||||
block* cmd = sbsh.single_cmd();
|
||||
if( cmd != nullptr && (cmd->args[0].raw == "%include" || cmd->args[0].raw == "%resolve") )
|
||||
{
|
||||
ret += cmd->generate(ind);
|
||||
}
|
||||
// regular substitution
|
||||
else
|
||||
{
|
||||
ret += '$';
|
||||
ret += sbsh.generate(ind);
|
||||
}
|
||||
ret += '$';
|
||||
ret += sbsh->generate(ind);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
52
src/main.cpp
52
src/main.cpp
|
|
@ -12,9 +12,9 @@
|
|||
#include "parse.hpp"
|
||||
#include "options.hpp"
|
||||
|
||||
int execute(block& sh, std::vector<std::string>& args)
|
||||
int execute(shmain* sh, std::vector<std::string>& args)
|
||||
{
|
||||
std::string data=sh.generate();
|
||||
std::string data=sh->generate();
|
||||
|
||||
std::string filename=ztd::exec("basename", args[0]).first;
|
||||
filename.pop_back();
|
||||
|
|
@ -76,10 +76,11 @@ int main(int argc, char* argv[])
|
|||
return 1;
|
||||
}
|
||||
|
||||
// resolve input
|
||||
std::string file;
|
||||
if(args.size() > 0)
|
||||
if(args.size() > 0) // argument provided
|
||||
{
|
||||
if(args[0] == "-")
|
||||
if(args[0] == "-" || args[0] == "/dev/stdin") //stdin
|
||||
{
|
||||
piped=true;
|
||||
file = "/dev/stdin";
|
||||
|
|
@ -89,55 +90,63 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
else
|
||||
{
|
||||
if(isatty(fileno(stdin)))
|
||||
if(isatty(fileno(stdin))) // stdin is interactive
|
||||
{
|
||||
print_help(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
else // is piped
|
||||
{
|
||||
piped=true;
|
||||
file = "/dev/stdin";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set origin file
|
||||
g_origin=file;
|
||||
add_include(file);
|
||||
|
||||
shmain* sh=nullptr;
|
||||
try
|
||||
{
|
||||
block sh(parse(import_file(file)));
|
||||
// parse
|
||||
sh = parse(import_file(file));
|
||||
// resolve shebang
|
||||
std::string curbin, binshebang;
|
||||
curbin=ztd::exec("basename", argv[0]).first;
|
||||
binshebang=ztd::exec("basename", sh.shebang).first;
|
||||
binshebang=ztd::exec("basename", sh->shebang).first;
|
||||
if(binshebang==curbin)
|
||||
sh.shebang="#!/bin/sh";
|
||||
if(options['e'])
|
||||
sh->shebang="#!/bin/sh";
|
||||
// process
|
||||
if(options['e']) // force exec
|
||||
{
|
||||
return execute(sh, args);
|
||||
}
|
||||
else if(options['c'])
|
||||
else if(options['c']) // force console out
|
||||
{
|
||||
std::cout << sh.generate();
|
||||
std::cout << sh->generate();
|
||||
}
|
||||
else if(options['o'])
|
||||
else if(options['o']) // file output
|
||||
{
|
||||
std::string destfile=options['o'];
|
||||
// resolve - to stdout
|
||||
if(destfile == "-")
|
||||
destfile = "/dev/stdout";
|
||||
std::ofstream(destfile) << sh.generate();
|
||||
ztd::exec("chmod", "+x", destfile);
|
||||
// output
|
||||
std::ofstream(destfile) << sh->generate();
|
||||
// don't chmod on /dev/
|
||||
if(destfile.substr(0,5) != "/dev/")
|
||||
ztd::exec("chmod", "+x", destfile);
|
||||
}
|
||||
else
|
||||
else // other process
|
||||
{
|
||||
if(binshebang == curbin)
|
||||
if(binshebang == curbin) // exec if shebang is program
|
||||
{
|
||||
return execute(sh, args);
|
||||
}
|
||||
else
|
||||
else // output otherwise
|
||||
{
|
||||
std::cout << sh.generate();
|
||||
std::cout << sh->generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -151,6 +160,9 @@ int main(int argc, char* argv[])
|
|||
std::cerr << e.what() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
if(sh!=nullptr)
|
||||
delete sh;
|
||||
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
1120
src/parse.cpp
1120
src/parse.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -4,54 +4,96 @@
|
|||
|
||||
#include <unistd.h>
|
||||
|
||||
block make_cmd(std::vector<std::string> args)
|
||||
const std::string cmd::empty_string="";
|
||||
|
||||
cmd* make_cmd(std::vector<std::string> args)
|
||||
{
|
||||
block cmd(block::cmd);
|
||||
cmd* ret = new cmd();
|
||||
ret->args = new arglist();
|
||||
for(auto it: args)
|
||||
{
|
||||
cmd.args.add(arg(it));
|
||||
ret->args->add(new arg(it));
|
||||
}
|
||||
return cmd;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> arglist::strargs(uint32_t start)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
for(uint32_t i=start; i<args.size(); i++)
|
||||
ret.push_back(args[i].raw);
|
||||
ret.push_back(args[i]->raw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void arg::setstring(std::string const& str)
|
||||
{
|
||||
for(auto it: sa)
|
||||
delete it;
|
||||
sa.resize(0);
|
||||
sa.push_back(subarg(str));
|
||||
sa.push_back(new subarg_string(str));
|
||||
raw = str;
|
||||
}
|
||||
|
||||
void condlist::add(pipeline const& pl, bool or_op)
|
||||
std::string arg::string()
|
||||
{
|
||||
if(sa.size() > 1 || sa[0]->type != subarg::s_string)
|
||||
return "";
|
||||
return sa[0]->generate(0);
|
||||
}
|
||||
|
||||
void condlist::add(pipeline* pl, bool or_op)
|
||||
{
|
||||
if(this->pls.size() > 0)
|
||||
this->or_ops.push_back(or_op);
|
||||
this->pls.push_back(pl);
|
||||
}
|
||||
|
||||
block* block::single_cmd()
|
||||
cmd* block::single_cmd()
|
||||
{
|
||||
if(this->type == block::subshell)
|
||||
if(this->type == block::block_subshell)
|
||||
{
|
||||
if( cls.size() == 1 && // only one condlist
|
||||
cls[0].pls.size() == 1 && // only one pipeline
|
||||
cls[0].pls[0].cmds.size() == 1 && // only one block
|
||||
cls[0].pls[0].cmds[0].type == block::cmd) // block is a command
|
||||
return &(cls[0].pls[0].cmds[0]); // return command
|
||||
return dynamic_cast<subshell*>(this)->single_cmd();
|
||||
}
|
||||
if(this->type == block::block_brace)
|
||||
{
|
||||
return dynamic_cast<brace*>(this)->single_cmd();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string arg::string()
|
||||
cmd* subshell::single_cmd()
|
||||
{
|
||||
if(sa.size() > 1 || sa[0].type != subarg::string)
|
||||
return "";
|
||||
return sa[0].val;
|
||||
if( cls.size() == 1 && // only one condlist
|
||||
cls[0]->pls.size() == 1 && // only one pipeline
|
||||
cls[0]->pls[0]->cmds.size() == 1 && // only one block
|
||||
cls[0]->pls[0]->cmds[0]->type == block::block_cmd) // block is a command
|
||||
return dynamic_cast<cmd*>(cls[0]->pls[0]->cmds[0]); // return command
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cmd* brace::single_cmd()
|
||||
{
|
||||
if( cls.size() == 1 && // only one condlist
|
||||
cls[0]->pls.size() == 1 && // only one pipeline
|
||||
cls[0]->pls[0]->cmds.size() == 1 && // only one block
|
||||
cls[0]->pls[0]->cmds[0]->type == block::block_cmd) // block is a command
|
||||
return dynamic_cast<cmd*>(cls[0]->pls[0]->cmds[0]); // return command
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void condlist::negate()
|
||||
{
|
||||
// invert commands
|
||||
for(uint32_t i=0; i<pls.size(); i++)
|
||||
pls[i]->negated = !pls[i]->negated;
|
||||
// invert bool operators
|
||||
for(uint32_t i=0; i<or_ops.size(); i++)
|
||||
or_ops[i] = !or_ops[i];
|
||||
}
|
||||
|
||||
std::string const& cmd::firstarg_raw()
|
||||
{
|
||||
if(args!=nullptr && args->size()>0)
|
||||
return args->args[0]->raw;
|
||||
return cmd::empty_string;
|
||||
}
|
||||
|
|
|
|||
14
src/util.cpp
14
src/util.cpp
|
|
@ -4,6 +4,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <ztd/shell.hpp>
|
||||
|
|
@ -120,19 +122,19 @@ std::string stringReplace(std::string subject, const std::string& search, const
|
|||
return subject;
|
||||
}
|
||||
|
||||
void printFormatError(ztd::format_error const& e, bool print_line)
|
||||
{
|
||||
printErrorIndex(e.data(), e.where(), e.what(), e.origin(), print_line);
|
||||
}
|
||||
|
||||
std::string repeatString(std::string const& str, uint32_t n)
|
||||
{
|
||||
std::string ret;
|
||||
for(uint32_t i=0; i<n; i++)
|
||||
ret += str;
|
||||
ret += str;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void printFormatError(ztd::format_error const& e, bool print_line)
|
||||
{
|
||||
printErrorIndex(e.data(), e.where(), e.what(), e.origin(), print_line);
|
||||
}
|
||||
|
||||
void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin, bool print_line)
|
||||
{
|
||||
int i=0, j=0; // j: last newline
|
||||
|
|
|
|||
Loading…
Reference in a new issue