From 5df79c53745fde5d6c3340a2979b1429cd5892c1 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 8 Oct 2011 20:30:28 +0200 Subject: Initial import of htcd system 1.0 Signed-off-by: Henrik Rydberg --- src/ops/basic.cc | 269 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/ops/comp.cc | 134 +++++++++++++++++++++++++ src/ops/express.cc | 173 +++++++++++++++++++++++++++++++++ src/ops/express.h | 79 +++++++++++++++ src/ops/latex.cc | 101 +++++++++++++++++++ src/ops/nnstyle.h | 53 ++++++++++ src/ops/operator.cc | 44 +++++++++ src/ops/operator.h | 97 +++++++++++++++++++ src/ops/string.cc | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ops/test.cc | 161 ++++++++++++++++++++++++++++++ 10 files changed, 1385 insertions(+) create mode 100644 src/ops/basic.cc create mode 100644 src/ops/comp.cc create mode 100644 src/ops/express.cc create mode 100644 src/ops/express.h create mode 100644 src/ops/latex.cc create mode 100644 src/ops/nnstyle.h create mode 100644 src/ops/operator.cc create mode 100644 src/ops/operator.h create mode 100644 src/ops/string.cc create mode 100644 src/ops/test.cc (limited to 'src/ops') diff --git a/src/ops/basic.cc b/src/ops/basic.cc new file mode 100644 index 0000000..b30e351 --- /dev/null +++ b/src/ops/basic.cc @@ -0,0 +1,269 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +OP1_IMPL(exp) { out<>atoi(R));} + +OP1_IMPL(bitnot) {out<<~atoi(a);} +OP2_IMPL(bitand) {out<<(atoi(L)&atoi(R)); } +OP2_IMPL(bitor) {out<<(atoi(L)|atoi(R)); } +OP2_IMPL(bitxor) {out<<(atoi(L)^atoi(R)); } + +OP2_IMPL(SP) {out<>, + "C style\n" + "Shift right\n" + "Syntax: (int) >> (int)\n" + "Returns: (int)\n" + ); + + OP_ADD(18,eq, + "Lexicographic equal\n" + "Syntax: (string) eq (string)\n" + "Returns: (int)\n" + ); + OP_ADD(18,eqn, + "Lexicographic equal, case insensitive\n" + "Syntax: (string) eqn (string)\n" + "Returns: (int)\n" + ); + OP_ADDN(18,eqf,==, + "Arithmetic equal\n" + "Syntax: (real) == (real)\n" + "Returns: (int)\n" + ); + OP_ADD(18,ne, + "Lexicographic not equal\n" + "Syntax: (string) ne (string)\n" + "Returns: (int)\n" + ); + OP_ADD(18,nen, + "Lexicographic not equal, case insensitive\n" + "Syntax: (string) nen (string)\n" + "Returns: (int)\n" + ); + OP_ADDN(18,nef,!=, + "Arithmetic not equal\n" + "Syntax: (real) != (real)\n" + "Returns: (int)\n" + ); + + OP_ADDN(16,bitand,&, + "C style\n" + "Bitwise AND\n" + "Syntax: (int) & (int)\n" + "Returns: (int)\n" + ); + OP_ADDN(14,bitxor,^, + "C style\n" + "Bitwise XOR\n" + "Syntax: (int) ^ (int)\n" + "Returns: (int)\n" + ); + OP_ADDN(12,bitor,|, + "C style\n" + "Bitwise OR\n" + "Syntax: (int) | (int)\n" + "Returns: (int)\n" + ); + + OP_ADDN(10,and,&&, + "C style\n" + "Logical AND\n" + "Syntax: (int) && (int)\n" + "Returns: (int)\n" + ); + OP_ADDN(9,xor,^^, + "Logical XOR\n" + "Syntax: (int) ^^ (int)\n" + "Returns: (int)\n" + ); + OP_ADDN(8,or,||, + "C style\n" + "Logical OR\n" + "Syntax: (int) || (int)\n" + "Returns: (int)\n" + ); + + /* + OP_ADD(3,SP, + "Whitespace padding\n" + "Syntax: a ws OR ws a OR a ws b\n" + "Returns: a b\n" + ); + */ + + M.add(new op_t(",",2,impl_comma, + "C style\n" + "Separate expression\n" + "Syntax: a , b\n" + "Returns: b\n" + )); + OP_ADD2(1,1,semi,;, + "C style\n" + "End expression\n" + "Syntax: a ; OR a ; b\n" + "Returns: nothing\n" + ); +} diff --git a/src/ops/comp.cc b/src/ops/comp.cc new file mode 100644 index 0000000..aa40246 --- /dev/null +++ b/src/ops/comp.cc @@ -0,0 +1,134 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +OP2_IMPL(lt) {out<<(L=R);} +OP2_IMPL(gt) {out<<(L>R);} +OP2_IMPL(ltn) {out<<(L.compare(R,cset_lcase)<0);} +OP2_IMPL(len) {out<<(L.compare(R,cset_lcase)<=0);} +OP2_IMPL(gen) {out<<(L.compare(R,cset_lcase)>=0);} +OP2_IMPL(gtn) {out<<(L.compare(R,cset_lcase)>0);} +OP2_IMPL(ltnn) {out<<(nncomp(L,R)<0);} +OP2_IMPL(lenn) {out<<(nncomp(L,R)<=0);} +OP2_IMPL(genn) {out<<(nncomp(L,R)>=0);} +OP2_IMPL(gtnn) {out<<(nncomp(L,R)>0);} +OP2_IMPL(ltf) {out<<(atof(L)=atof(R));} +OP2_IMPL(gtf) {out<<(atof(L)>atof(R));} + +void opAddComp(opmap& M) +{ + OP_ADD(20,lt, + "Lexicographic less than\n" + "Syntax: (string) lt (string)\n" + "Returns: (int)\n" + ); + OP_ADD(20,le, + "Lexicographic less or equal\n" + "Syntax: (string) le (string)\n" + "Returns: (int)\n" + ); + OP_ADD(20,ge, + "Lexicographic greater or equal\n" + "Syntax: (string) ge (string)\n" + "Returns: (int)\n" + ); + OP_ADD(20,gt, + "Lexicographic greater than\n" + "Syntax: (string) gt (string)\n" + "Returns: (int)\n" + ); + + OP_ADD(20,ltn, + "Lexicographic less than, case insensitive\n" + "Syntax: (string) ltn (string)\n" + "Returns: (int)\n" + ); + OP_ADD(20,len, + "Lexicographic less or equal, case insensitive\n" + "Syntax: (string) len (string)\n" + "Returns: (int)\n" + ); + OP_ADD(20,gen, + "Lexicographic greater or equal, case insensitive\n" + "Syntax: (string) gen (string)\n" + "Returns: (int)\n" + ); + OP_ADD(20,gtn, + "Lexicographic greater than, case insensitive\n" + "Syntax: (string) gtn (string)\n" + "Returns: (int)\n" + ); + + OP_ADD(20,ltnn, + "Lexicographic less than, NN-style\n" + "Syntax: (string) ltnn (string)\n" + "Returns: (int)\n" + "\n" + "NN-style compares names as \n" + ); + OP_ADD(20,lenn, + "Lexicographic less or equal, NN-style\n" + "Syntax: (string) lenn (string)\n" + "Returns: (int)\n" + "\n" + "NN-style compares names as \n" + ); + OP_ADD(20,genn, + "Lexicographic greater or equal, NN-style\n" + "Syntax: (string) genn (string)\n" + "Returns: (int)\n" + "\n" + "NN-style compares names as \n" + ); + OP_ADD(20,gtnn, + "Lexicographic greater than, NN-style\n" + "Syntax: (string) gtnn (string)\n" + "Returns: (int)\n" + "\n" + "NN-style compares names as \n" + ); + + OP_ADDN(20,ltf,<, + "Arithmetic less than\n" + "Syntax: (real) < (real)\n" + "Returns: (int)\n" + ); + OP_ADDN(20,lef,<=, + "Arithmetic less or equal\n" + "Syntax: (real) <= (real)\n" + "Returns: (int)\n" + ); + OP_ADDN(20,gef,>=, + "Arithmetic greater or equal\n" + "Syntax: (real) >= (real)\n" + "Returns: (int)\n" + ); + OP_ADDN(20,gtf,>, + "Arithmetic greater than\n" + "Syntax: (real) > (real)\n" + "Returns: (int)\n" + ); + +} diff --git a/src/ops/express.cc b/src/ops/express.cc new file mode 100644 index 0000000..2cd3114 --- /dev/null +++ b/src/ops/express.cc @@ -0,0 +1,173 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +const mstring sp_tag="SP"; + +//////////////////////////////////////////////////////////////// + +uniheap expr_t::tree; +void* expr_t::operator new(size_t n) { return tree.push(); } +void expr_t::operator delete(void* p) { tree.pop(p); } + +//////////////////////////////////////////////////////////////// + +inline int precedence(const expr_t* root,const op_t* op) +{ + if(!root->op) return 1; + else if(!op) return 0; + else if(root->left) { + if(root->right) return op->pre2&&root->op->pre2>=op->pre2; + else return root->op->pre2>=op->pre1; + } + else { + if(root->right) return op->pre2&&root->op->pre1>=op->pre2; + else return root->op->pre1>=op->pre1; + } +} + +static int ins_node_sp(expr_t*& root,op_env& env, + const sref& in,const op_t* op) throw(merror_t) +{ + if(root==0) { root=new expr_t(in,op); root->expand(env); return 1; } + else if(precedence(root,op)) { + if(op) { root=new expr_t(in,op,root); return 1; } else return 0; + } + else return ins_node_sp(root->right,env,in,op); +} + +static void ins_node(expr_t*& root,op_env& env,const sref& in) throw(merror_t) +{ + const op_t* op=env.ops->get(in); + if(!ins_node_sp(root,env,in,op)) { + if(!ins_node_sp(root,env,sp_tag,env.ops->get(sp_tag))) + THROW("ops: ("<expr<<" ["<trav(out,n-1); + for(int i=0;i<3*n;i++) out.put(' '); + out<<"["< "<trav(out,n-1); +} + +void expr_t::expand(op_env& env) throw(merror_t) +{ + if(!op) { + sref first,rest=expr; + env.split(first,rest); + if(first!=expr) { + do ins_node(right,env,first); + while(env.split(first,rest)); + } + } +} + +/////////////////////////////////////////////////////////////// + +void expr_t::eval(mstream& out,op_env& env,int opt) throw(merror_t) +{ + if(op) { + if(left) { + if(op->left>1) { + if(left->status&opt) { + swrite sw(left->result); + left->eval(sw,env,opt); + } + } + else if(!op->left) + THROW("ops: ("<expr<<" ["<op) + THROW("ops: (["<expr<<"] "<status=OP_LOCAL; + left->result=left->expr; + } + } + if(right) { + if(op->right>1) { + if(right->status&opt) { + swrite sw(right->result); + right->eval(sw,env,opt); + } + } + else if(!op->right) + THROW("ops: ("<expr<<" ["<op) + THROW("ops: (["<expr<<"] "<status=OP_LOCAL; + right->result=right->expr; + } + } + if(left) { + if(right) { + status=left->status|right->status; + if((status&OP_NINIT)==0) op->f2(out,env,left->result,right->result); + } + else if(!op->f1) + THROW("ops: ("<expr<<" "<status; + if((status&OP_NINIT)==0) op->f1(out,env,left->result); + } + } + else if(right) { + if(!op->f1) + THROW("ops: ([L] "<expr<<"): missing L argument") + else { + status=right->status; + if((status&OP_NINIT)==0) op->f1(out,env,right->result); + } + } + else THROW("ops: ["<eval(out,env,opt); + status=right->status; + } + else env.term(out,this); + } + if(status&OP_NINIT) THROW("ops: unfinished expression ["< +#include +#include + +const int OP_LOCAL=1; +const int OP_GLOBAL=2; +const int OP_NINIT=4; +const int OP_ALL=OP_LOCAL|OP_GLOBAL|OP_NINIT; + +class expr_t { +public: + sref expr; + const op_t* op; + int status; + mstring result; + expr_t *left,*right; + + expr_t(): + expr(),op(0),status(OP_ALL),result(),left(0),right(0) {} + expr_t(const expr_t& x): + expr(),op(0),status(OP_ALL),result(),left(0),right(0) { copy(x); } + expr_t(const sref& s): + expr(s),op(0),status(OP_ALL),result(),left(0),right(0) {} + expr_t(const sref& s,const op_t* o): + expr(s),op(o),status(OP_ALL),result(),left(0),right(0) {} + expr_t(const sref& s,const op_t* o,expr_t* p): + expr(s),op(o),status(OP_ALL),result(),left(p),right(0) {} + ~expr_t() { delete left; delete right; } + + void clear(); + expr_t& operator=(const expr_t& x) { clear(); copy(x); return *this; } + expr_t& operator=(const sref& in) { clear(); expr=in; return *this; } + + void trav(mstream& out,int n); + void expand(op_env& env) throw(merror_t); + void eval(mstream& out,op_env& env,int opt) throw(merror_t); + + static void* operator new(size_t n); + static void operator delete(void* p); +protected: + void copy(const expr_t& x); + static uniheap<36> tree; +}; + +//////////////////////////////////////////////////////////// + +struct op_env { + opmap* ops; + + op_env() : ops(0) {} + op_env(opmap& map) : ops(&map) {} + + virtual int split(sref& first,sref& rest) throw(merror_t) { return 0; } + virtual void term(mstream& out,expr_t* x) throw(merror_t) { x->status=0; } +}; + +#endif diff --git a/src/ops/latex.cc b/src/ops/latex.cc new file mode 100644 index 0000000..01ccfc0 --- /dev/null +++ b/src/ops/latex.cc @@ -0,0 +1,101 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +OP1_IMPL(minus) {out<<"-"<"<";} +OP1_IMPL(pow) {out<<""<";} +OP2_IMPL(sub) {out<"<";} +OP1_IMPL(sub) {out<<""<";} +OP2_IMPL(div) {out<"<=,"greater or equal"); + OP_ADDN(20,gt,>,"greater than"); + + OP_ADDN(18,eq,==,"equal"); + OP_ADDN(18,ne,!=,"not equal"); + OP_ADDN(18,equiv,===,"equivalent"); + OP_ADDN(18,sim,~,"similar"); + OP_ADDN(18,simeq,~=,"similar equal"); + + OP_ADD(10,and,"logic and"); + OP_ADD(9,xor,"logic xor"); + OP_ADD(8,or,"logic or"); + + OP_ADDN(4,assign,=,"assignment"); + + OP_ADD(3,SP,"Whitespace padding"); + + OP_ADD2(1,1,semi,;,"concatenation"); +} diff --git a/src/ops/nnstyle.h b/src/ops/nnstyle.h new file mode 100644 index 0000000..4b8be5e --- /dev/null +++ b/src/ops/nnstyle.h @@ -0,0 +1,53 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef NNSTYLEH +#define NNSTYLEH + +#include + +const charset cset_wsdot=cset_ws|'.'; + +inline mstring nncase(const sref& b) +{ + static const mstring comma_tag(","),and_tag("and"); + mstring acc,a,name; + sref next,first,rest=b; + while(Split(first,rest,cset_wsdot)) { + if(first==comma_tag||eqn(first,and_tag)) continue; + (name=first.left_first(comma_tag)).tosim(); + name[0]=cset_ucase[name[0]]; + next=First(rest); + if(first.back()==','||next.empty()||*next==','||eqn(next,and_tag)) { + a.insert(0,name); + if(acc.nempty()) { acc+=' '; acc+=and_tag; acc+=' '; } + acc+=a; + a.clear(); + } + else { a+=' '; a+=name[0]; a+='.'; } + } + return acc; +} + +inline int nncomp(const sref& L,const sref& R) +{ + return nncase(L).compare(nncase(R)); +} + +#endif diff --git a/src/ops/operator.cc b/src/ops/operator.cc new file mode 100644 index 0000000..f668340 --- /dev/null +++ b/src/ops/operator.cc @@ -0,0 +1,44 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +using namespace std; + +void opmap::clear() { + for(iterator p=begin();p!=end();p++) delete *p; + mrvec::clear(); +} +void opmap::erase(iterator p) { + delete *p; mrvec::erase(p); +} + +const op_t* opmap::get(const sref& t) const +{ + pair p= + equal_range(begin(),end(),(opmap_t)0,comp_t(t)); + return p.first!=p.second?*p.first:0; +} + +const op_t* opmap::add(op_t* op) +{ + pair p=equal_range(begin(),end(),(opmap_t)0,comp_t(op->name)); + if(p.first!=p.second) { delete *p.first; return *p.first=op; } + else return *insert(p.second,op); +} diff --git a/src/ops/operator.h b/src/ops/operator.h new file mode 100644 index 0000000..d4a7af8 --- /dev/null +++ b/src/ops/operator.h @@ -0,0 +1,97 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef OPERATORH +#define OPERATORH + +#include +#include + +const mstring lt_tag="lt"; + +/////////////////////////////////////////////// + +class op_env; +struct op_t { + typedef void (*op1_t)(mstream&,op_env&,const sref&); + typedef void (*op2_t)(mstream&,op_env&,const sref&,const sref&); + + mstring name,desc; + int pre1,pre2; + int left,right; + op1_t f1; op2_t f2; + + op_t(const mstring& s,int p1,int p2,int l,int r,op1_t op1,op2_t op2,const mstring& d): + name(s),pre1(p1),pre2(p2),left(l),right(r),f1(op1),f2(op2),desc(d) {} + op_t(const mstring& s,int p1,int p2,op1_t op1,op2_t op2,const mstring& d): + name(s),pre1(p1),pre2(p2),left(2),right(2),f1(op1),f2(op2),desc(d) {} + op_t(const mstring& s,int p,op1_t op,const mstring& d): + name(s),pre1(p),pre2(0),left(0),right(2),f1(op),f2(0),desc(d) {} + op_t(const mstring& s,int p,op2_t op,const mstring& d): + name(s),pre1(0),pre2(p),left(2),right(2),f1(0),f2(op),desc(d) {} +}; + +#define OP1_IMPL(n) \ +static void impl_##n(mstream& out,op_env& env,const sref& a) +#define OP2_IMPL(n) \ +static void impl_##n(mstream& out,op_env& env,const sref& L,const sref& R) + +//////////////////////////////////////////////////////////// + +typedef op_t* opmap_t; + +struct opmap : public mrvec { + typedef mrvec::iterator iterator; + typedef mrvec::const_iterator const_iterator; + + struct comp_t { + sref key; + comp_t(const sref& skey) : key(skey) {} + bool operator()(const op_t* a,const op_t* b) const { + return (a?((const sref&)a->name):key)<(b?((const sref&)b->name):key); + } + }; + + opmap() : mrvec() {} + ~opmap() { clear(); } + + void clear(); // overrides parent + void erase(iterator p); // overrides parent + + const op_t* get(const sref& t) const; + const op_t* add(op_t* op); +}; + +#define OP_ADD(p,f,d) M.add(new op_t(#f,p,impl_##f,d)) +#define OP_ADDN(p,f,n,d) M.add(new op_t(#n,p,impl_##f,d)) +#define OP_ADD2(p1,p2,f,n,d) M.add(new op_t(#n,p1,p2,impl_##f,impl_##f,d)) + +/////////////////////////////////////////// + +void opAddBasic(opmap& map); +void opAddComp(opmap& map); +void opAddString(opmap& map); +inline void opAddHEXP(opmap& map) { + opAddBasic(map); + opAddComp(map); + opAddString(map); +} +void opAddLatex(opmap& map); + +#endif diff --git a/src/ops/string.cc b/src/ops/string.cc new file mode 100644 index 0000000..76b7e72 --- /dev/null +++ b/src/ops/string.cc @@ -0,0 +1,274 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +OP2_IMPL(intersect) { mset a(L),b(R),c; c.Intersection(a,b); out<0&&Split(first,rest)); + out<=0);} +OP2_IMPL(cntn) {out<<(L.find(R,cset_lcase)>=0);} + +OP2_IMPL(concat) {out< \n" + ); + OP_ADD(32,skipws, + "Skip whitespace\n" + "Syntax: skipws (string)\n" + "Returns: (string)\n" + "\n" + "Skips trailing whitespace\n" + ); + + OP_ADD(32,first, + "First element in list\n" + "Syntax: first (list)\n" + "Returns: (string)\n" + "\n" + "Elements are separated by whitespace\n" + ); + OP_ADD(32,last, + "Last element in list\n" + "Syntax: last (list)\n" + "Returns: (string)\n" + "\n" + "Elements are separated by whitespace\n" + ); + OP_ADD(32,rest, + "Rest of elements in list\n" + "Syntax: rest (list)\n" + "Returns: (list)\n" + "\n" + "Elements are separated by whitespace\n" + ); + OP_ADD(32,count, + "Count elements in list\n" + "Syntax: count (list)\n" + "Returns: (int)\n" + "\n" + "Elements are separated by whitespace\n" + ); + + OP_ADD(30,nth, + "Nth element in list\n" + "Syntax: (list) nth (int)\n" + "Returns: (string)\n" + "\n" + "First element is denoted 1\n" + "Elements out of range returns empty\n" + "Elements are separated by whitespace\n" + ); + OP_ADD(30,which, + "Which element in list\n" + "Syntax: (list) a which (string) b\n" + "Returns: (int)\n" + "\n" + "Which element in a is b (0 if not found)\n" + "First element is denoted 1\n" + "Elements are separated by whitespace\n" + ); + + OP_ADD(28,left, + "Left of substring\n" + "Syntax: (string) a left (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the left of first b, of a if b not found in a\n" + ); + OP_ADD(28,leftand, + "Left of substring inclusive\n" + "Syntax: (string) a leftand (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the left of first b inclusive, of a if b not found in a\n" + ); + OP_ADD(28,right, + "Right of substring inclusive\n" + "Syntax: (string) a right (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the right of first b inclusive, of empty if b not found in a\n" + ); + OP_ADD(28,past, + "Right of substring\n" + "Syntax: (string) a past (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the right of first b, of empty if b not found in a\n" + ); + + OP_ADD(28,rleft, + "Left of substring (reversed)\n" + "Syntax: (string) a rleft (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the left of last b, of a if b not found in a\n" + ); + OP_ADD(28,rleftand, + "Left of substring inclusive, (reversed)\n" + "Syntax: (string) a rleftand (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the left of last b inclusive, of a if b not found in a\n" + ); + OP_ADD(28,rright, + "Right of substring inclusive (reversed)\n" + "Syntax: (string) a rright (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the right of last b inclusive, of empty if b not found in a\n" + ); + OP_ADD(28,rpast, + "Right of substring (reversed)\n" + "Syntax: (string) a rpast (string) b\n" + "Returns: (string)\n" + "\n" + "Everything in a to the right of last b, of empty if b not found in a\n" + ); + + OP_ADDN(24,concat,++, + "String concatenation\n" + "Syntax: (string) ++ (string)\n" + "Returns: (string)\n" + ); + OP_ADDN(24,concats,+++, + "List concatenation\n" + "Syntax: (list) +++ (list)\n" + "Returns: (list)\n" + "\n" + "Lists are concatenated with space\n" + ); + + OP_ADD(18,cnt, + "Contains substring\n" + "Syntax: (string) a cnt (string) b\n" + "Returns: (int)\n" + "\n" + "Nonzero if b found in a\n" + ); + OP_ADD(18,cntn, + "Contains substring, case insensitive\n" + "Syntax: (string) a cnt (string) b\n" + "Returns: (int)\n" + "\n" + "Nonzero if b found in a\n" + ); + OP_ADD(18,eqnn, + "NN-style equal\n" + "Syntax: (string) eqnn (string)\n" + "Returns: (int)\n" + "\n" + "NN-style converts names to \n" + ); + OP_ADD(18,nenn, + "NN-style not equal\n" + "Syntax: (string) eqnn (string)\n" + "Returns: (int)\n" + "\n" + "NN-style converts names to \n" + ); + + OP_ADDN(10,intersect,&&&, + "List intersection\n" + "Syntax: (list) a &&& (list) b\n" + "Returns: (list)\n" + "\n" + "Finds the set intersection of a and b\n" + ); + OP_ADDN(9,difference,---, + "List difference\n" + "Syntax: (list) a &&& (list) b\n" + "Returns: (list)\n" + "\n" + "Finds the set difference of a and b\n" + ); + OP_ADDN(9,union,|||, + "List union\n" + "Syntax: (list) a &&& (list) b\n" + "Returns: (list)\n" + "\n" + "Finds the set union of a and b\n" + ); +} diff --git a/src/ops/test.cc b/src/ops/test.cc new file mode 100644 index 0000000..b6058fc --- /dev/null +++ b/src/ops/test.cc @@ -0,0 +1,161 @@ +/************************************************************************* + * + * HTCd - Copyright (C) 1998-2006 Henrik Rydberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +using namespace std; + +static fp_stream mout(stdout),merr(stderr); + +struct tt_env : public op_env { + sspile var; + tt_env(opmap& map) : op_env(map) {} + int split(sref& first,sref& rest) throw(merror_t) { + static const charset spec("+-*%/<=>^_!~&|,?:;"); + static const charset delim("()\"\\"); + static const charset specws=spec|delim|cset_ws; + int s; + rest=rest.right_first_not_of(cset_ws); + if((s=rest.skip(cset_quotes))>0) { + first=rest.left(s); + rest=rest.right(s); + } + else if((s=rest.skip(cset_para))>0) { + first=Trim(rest.left(s),cset_para); + rest=rest.right(s); + } + else if((s=rest.skip(cset_braces))>0) { + first=rest.left(s); + rest=rest.right(s); + } + else if(spec.test(*rest)) { + first=rest.left_first_not_of(spec); + rest=rest.adv(first); + } + else { + first=rest.left_first_of(specws); + rest=rest.adv(first); + } + return first.nempty(); + } + void term(mstream& out,expr_t* x) throw(merror_t) { + if(x->expr.empty()) { + x->status=0; + } + else if(x->expr.skip(cset_quotes)==x->expr.size()) { + out<expr(1,-3); + x->status=0; + } + else if(x->expr.find_not_of(cset_real)<0) { + out<expr; + x->status=0; + } + else { + for(sspile::iterator s=var.begin();s!=var.end();s++) + if(s->first==x->expr) { out<second; x->status=OP_LOCAL; break; } + } + } +}; + +#define TT_IMPL(n) \ +static void impl_##n(mstream& out,tt_env& env,const sref& L,const sref& R) +#define TT_ADDN(p,f,n,d) \ +M.add(new op_t(#n,0,p,1,2,0,(op_t::op2_t)impl_##f,d)) + +TT_IMPL(assign) { + sspile& var=env.var; + for(sspile::iterator p=var.begin();p!=var.end();p++) + if(p->first==L) { p->second=R; return; } + var.push_back(sstring(L,R)); +} + +TT_IMPL(incr) { + sspile& var=env.var; + for(sspile::iterator p=var.begin();p!=var.end();p++) + if(p->first==L) { p->second=itoa(atoi(p->second)+atoi(R)); break; } +} + +TT_IMPL(decr) { + sspile& var=env.var; + for(sspile::iterator p=var.begin();p!=var.end();p++) + if(p->first==L) { p->second=itoa(atoi(p->second)-atoi(R)); break; } +} + +inline void opAddTT(opmap& M) { + TT_ADDN(4,assign,=,"C style"); + TT_ADDN(4,assign,:=,"new var"); + TT_ADDN(4,incr,+=,"C style"); + TT_ADDN(4,decr,-=,"C style"); +} + +main(int argc,char* argv[]) try +{ + opmap ops; + opAddHEXP(ops); + opAddTT(ops); + tt_env env(ops); + mstring buf; + sref_t line; + expr_t expr; + if(argc>1) { + buf.load(sref(argv[1])); + sref first,rest=buf; + Splitln(first,rest); + if(first.left(2)!=sref("#!")) rest=buf; + (expr=buf).expand(env); + expr.eval(mout,env,OP_ALL); + mout<<"\n"; + } + else { + while(1) { + merr<<"ops>"; + cin.getline(line,sizeof(sref_t)); + sref first,rest(line); + Split(first,rest); + if(first==sref("exit")) { + break; + } + else if(first==sref("tree")) { + expr.trav(mout,12); + } + else if(first==sref("eval")) { + expr.eval(mout,env,OP_ALL); + mout<<"\n"; + } + else { + buf=line; + try { + (expr=buf).expand(env); + expr.eval(mout,env,OP_ALL); + mout<<"\n"; + } + catch(const merror_t& e) { + merr<