// HIGHER SUBLEQ compiler // Oleg Mazonka 2009 // http://mazonka.com/subleq/ // Usage: hsq [options] [files] /** Content (autogenerated by http://mazonka.com/subleq/content.cpp) 1 Standard headers ..................................... (137-169:32) 2 Driver ............................................... (170-440) 2.1 Driver command line options ...................... (171-195:24) 2.2 Driver forward declarations ...................... (196-224:28) 2.3 main() ........................................... (225-307:82) 2.4 Driver functions implementation .................. (308-440) 2.4.1 usage ........................................ (309-327:18) 2.4.2 parse command line options ................... (328-370:42) 2.4.3 fill buckets ................................. (371-430:59) 2.4.4 base name .................................... (431-440:9) 3 Headers .............................................. (441-1198) 3.1 Bignum header .................................... (444-521) 3.1.1 Unsigned number .............................. (447-497:50) 3.1.2 Signed number ................................ (498-521:23) 3.2 Utility declarations ............................. (522-536:14) 3.3 Itr headers ...................................... (537-1093) 3.3.1 ITR class .................................... (541-653:112) 3.3.2 ITR goodies .................................. (654-683:29) 3.3.3 ITR derived classes .......................... (684-1078) 3.3.3.1 ITR root ................................. (686-711:25) 3.3.3.2 Constants and variables, primaries ....... (712-792:80) 3.3.3.3 Imperatives .............................. (793-857:64) 3.3.3.4 Declarations ............................. (858-908:50) 3.3.3.5 Expressions .............................. (909-1078:169) 3.3.4 Library manager declarations ................. (1079-1093:14) 3.4 Emulator ......................................... (1094-1132:38) 3.5 Compiler ......................................... (1133-1135:2) 3.6 Parser ........................................... (1136-1198:62) 4 Bignum implementation ................................ (1199-1586) 4.1 GCD .............................................. (1202-1218:16) 4.2 Number ........................................... (1219-1444:225) 4.3 Rebasing ......................................... (1445-1478:33) 4.4 Integer .......................................... (1479-1586:107) 5 Utility implementation ............................... (1587-1734:147) 6 Emulator ............................................. (1735-1860:125) 7 Assembly compiler .................................... (1861-2324:463) 8 HSQ compiler ......................................... (2325-7057) 8.1 Itr dump ......................................... (2329-2336:7) 8.2 General hsq functions ............................ (2337-2961:624) 8.3 Lib manager ...................................... (2962-3175:213) 8.4 Compiler ......................................... (3176-5169) 8.4.1 General classes and utilities ................ (3178-3413:235) 8.4.2 Compile functions ............................ (3414-5169) 8.4.2.1 Low IO ................................... (3416-3453:37) 8.4.2.2 Declaration .............................. (3454-3514:60) 8.4.2.3 Declarator ............................... (3515-3614:99) 8.4.2.4 Function ................................. (3615-3674:59) 8.4.2.5 Constant evaluator ....................... (3675-3724:49) 8.4.2.6 Unary Expression ......................... (3725-3884:159) 8.4.2.7 Variable ................................. (3885-3904:19) 8.4.2.8 Assignment Expression .................... (3905-4139:234) 8.4.2.9 Constant ................................. (4140-4152:12) 8.4.2.10 Label ................................... (4153-4173:20) 8.4.2.11 Root .................................... (4174-4247:73) 8.4.2.12 Block ................................... (4248-4260:12) 8.4.2.13 String .................................. (4261-4282:21) 8.4.2.14 Statement ............................... (4283-4293:10) 8.4.2.15 Postfix Expression ...................... (4294-4467:173) 8.4.2.16 Expression List ......................... (4468-4483:15) 8.4.2.17 Keyword Statement ....................... (4484-4750) 8.4.2.17.1 Top function ........................ (4485-4505:20) 8.4.2.17.2 break, continue ..................... (4506-4538:32) 8.4.2.17.3 if .................................. (4539-4596:57) 8.4.2.17.4 for ................................. (4597-4644:47) 8.4.2.17.5 while ............................... (4645-4692:47) 8.4.2.17.6 goto ................................ (4693-4721:28) 8.4.2.17.7 return .............................. (4722-4750:28) 8.4.2.18 Expression .............................. (4751-4766:15) 8.4.2.19 Labeled Statement ....................... (4767-4777:10) 8.4.2.20 Relational Exression .................... (4778-4850:72) 8.4.2.21 Equality Expression ..................... (4851-4972:121) 8.4.2.22 Logical-And Expression .................. (4973-5020:47) 8.4.2.23 Logical-Or Expression ................... (5021-5070:49) 8.4.2.24 Conditional Expression .................. (5071-5169:98) 8.5 Static Evaluator ................................. (5170-5512) 8.5.1 Conditional expression ....................... (5172-5208:36) 8.5.2 Pair expressions ............................. (5209-5246:37) 8.5.3 Array size ................................... (5247-5276:29) 8.5.4 Unary expressions ............................ (5277-5378:101) 8.5.5 General evaluator switch ..................... (5379-5403:24) 8.5.6 Warning function ............................. (5404-5416:12) 8.5.7 Multiplication ............................... (5417-5456:39) 8.5.8 General multiplicative switch ................ (5457-5469:12) 8.5.9 Boolean conversion ........................... (5470-5512:42) 8.6 Parser ........................................... (5513-7057) 8.6.1 Parse root ................................... (5551-5594:43) 8.6.2 Declaration .................................. (5595-5647:52) 8.6.3 TypeName ..................................... (5648-5664:16) 8.6.4 Declarator ................................... (5665-5850) 8.6.4.1 Global ................................... (5666-5741:75) 8.6.4.2 Extern ................................... (5742-5771:29) 8.6.4.3 Stack .................................... (5772-5850:78) 8.6.5 Function decl ................................ (5851-5921:70) 8.6.6 ParamTypeList ................................ (5922-5948:26) 8.6.7 Block ........................................ (5949-5979:30) 8.6.8 Statement .................................... (5980-6030:50) 8.6.9 Keyword statement ............................ (6031-6266) 8.6.9.1 Loop for ................................. (6070-6125:55) 8.6.9.2 Loop while ............................... (6126-6155:29) 8.6.9.3 Clause if ................................ (6156-6198:42) 8.6.9.4 Goto ..................................... (6199-6237:38) 8.6.9.5 Continue ................................. (6238-6251:13) 8.6.9.6 Break .................................... (6252-6266:14) 8.6.10 Labeled statement ........................... (6267-6298:31) 8.6.11 Expression .................................. (6299-6329:30) 8.6.12 Assignment expression ....................... (6330-6362:32) 8.6.13 Assignment operator ......................... (6363-6378:15) 8.6.14 Equal expression ............................ (6379-6408:29) 8.6.15 Ralational expression ....................... (6409-6439:30) 8.6.16 Additive expression ......................... (6440-6470:30) 8.6.17 Multiplicative expression ................... (6471-6534:63) 8.6.18 Unary expression ............................ (6535-6573:38) 8.6.19 Postfix expression .......................... (6574-6640:66) 8.6.20 Comma expression ............................ (6641-6675:34) 8.6.21 Primary expression .......................... (6676-6744:68) 8.6.22 Input/Output operator ....................... (6745-6777:32) 8.6.23 Conditional expression ...................... (6778-6814:36) 8.6.24 Logical Or expression ....................... (6815-6844:29) 8.6.25 Logical And expression ...................... (6845-6875:30) 8.6.26 Stack replacement ........................... (6876-6909:33) 8.6.27 Context implementation ...................... (6910-7057) 8.6.27.1 Dump .................................... (6911-6949:38) 8.6.27.2 Add variable ............................ (6950-6973:23) 8.6.27.3 Get variable ............................ (6974-6999:25) 8.6.27.4 Get global variable ..................... (7000-7019:19) 8.6.27.5 Resolve variable ........................ (7020-7041:21) 8.6.27.6 Add param list .......................... (7042-7057:15) **/ /** 1 Standard headers **/ #include #include #include #include #include #include #include #include #include #include #include #include #include using std::cout; using std::string; using std::vector; using std::istringstream; using std::map; using std::set; using std::list; using std::pair; using std::make_pair; #define LOGO "Oleg Mazonka 2009 Higher Subleq Compiler Version 0.2.11" /** 2 Driver **/ /** 2.1 Driver command line options **/ namespace driver{ string mainfilename; vector hsq_bucket_nm; vector asq_bucket_nm; vector sq_bucket_nm; vector hsq_bucket_text; vector asq_bucket_text; vector sq_bucket_text; bool logo = true; bool usebignum = false; int action = 0; // 0-execute; 1-sq, 2-asm; 3-itr bool bcin = false; bool bcout = false; int langflag = 0; // 0-unknown; 1-hsq; 2-asq; 3-sq } // driver /** 2.2 Driver forward declarations **/ namespace driver{ int tmain(int ac, char *av[]); void usage(); void parseoptions(int ac, char *av[]); string loadfile(const string &file); string loadstream(std::istream &in); void fillbuckets(); void cutmainfilename(); string getlogo(){ return LOGO; } } //driver namespace hsqcomp{ string hsqcompile(vector &vname, vector &vtext); string itrcompile(vector &vname, vector &vtext); } // compiler namespace asqcomp{ string asqcompile(vector &vtext); } // asqcomp namespace emulator{ void sqemulate(vector &vtext, bool big); } // emulator /** 2.3 main() **/ int main(int ac, char *av[]) { try{ return driver::tmain(ac,av); } catch(string e) { std::cerr<<"Error: "< input HSQ (defalut, default for *.hsq)\n" " -m input assembly (default for *.asq)\n" " -s input subleq code (default for *.sq)\n" " -i input from stdin\n" " -o output to stdout\n" " -n nologo (defalut with -o)\n" " -b use bignum on emulation (default int)\n"; } /** 2.4.2 parse command line options **/ void driver::parseoptions(int ac, char *av[]) { langflag = 0; for( int i=1; i 3 && nm.substr(sz-3)==".sq" ) sq_bucket_nm.push_back(nm); else if( nm.size() > 4 && nm.substr(sz-4)==".asq" ) asq_bucket_nm.push_back(nm); else hsq_bucket_nm.push_back(nm); } } } /** 2.4.3 fill buckets **/ string driver::loadstream(std::istream &in) { string r; for(;;) { char c; in.get(c); if( !in ) break; r += c; } return r; } string driver::loadfile(const string &file) { if( file=="" ) return ""; string text; std::ifstream in(file.c_str()); if( !in ) throw "cannot open "+file; return loadstream(in); } void driver::fillbuckets() { for( size_t i=0; i x; void comb(); int at(int i) const; int & ac(int i); number & shift(int k); public: number() {} explicit number(const string &s); number(int); // not explicit to allow lookalike arithmetics // number(const number&); // default string str(unsigned pad=0) const; int toint() const; number & operator-=(const number &n); number & operator+=(const number &n); number & operator++(){ return *this+=1; } number operator++(int){ number t(*this); ++*this; return t; } number & operator*=(const number &n); number & operator%=(const number &n); number operator*(const number &n) const { number t(*this); return t*=n; } number operator+(const number &n) const { number t(*this); return t+=n; } number operator-(const number &n) const { number t(*this); return t-=n; } number operator%(const number &n) const { number t(*this); return t%=n; } bool operator<(const number &n) const; bool operator>(const number &n) const; bool operator==(const number &n) const; bool operator!=(const number &n) const { return !(*this==n); } bool operator>=(const number &n) const { return !(*thisn); } void divMod(const number &n, number * divisor); void swap(number & n){ x.swap(n.x); } }; inline int number::at(int i) const { return (i<0||i>=(int)x.size())?0:x[i]; } inline int & number::ac(int i){ while(i>=(int)x.size()) x.push_back(0); return x[i]; } number gcd(number big, number small); std::vector rebase(number n, int base); number rebase(std::vector v, int base); /** 3.1.2 Signed number **/ class inumber { number n; bool neg; public: inumber(int); inumber(string s); string str() const; int toint() const; inumber & operator++(){ return *this-=-1; } inumber operator++(int){ inumber t(*this); ++*this; return t; } bool operator<(const inumber &n) const; bool operator>=(const inumber &n) const { return !(*this(const inumber &n) const; bool operator<=(const inumber &n) const { return !(*this>n); } bool operator==(const inumber &n) const; inumber & operator-=(const inumber &n); inumber & operator+=(const inumber &n); inumber operator-() const; }; } // big /** 3.2 Utility declarations **/ namespace ut{ string logtag_function(const char* file, int line); string i2a(int x); int a2i(string s); void replaceAll(string &s, const string &r, const string &to); string prn(const string &x); string str_mult(const string &x, const string &y); string str_div(const string &x, const string &y); string str_mod(const string &x, const string &y); string str_add(const string &x, const string &y); string str_sub(const string &x, const string &y); bool str_eq(const string &x, const string &y); } // ut /** 3.3 Itr headers **/ namespace hsqcomp{ /** 3.3.1 ITR class **/ class ItrRoot; class ItrFunc; class ItrId; class Context; struct parseinfo; struct cplinfo{ string code; string res; string var; // l-value string ref; // l-value explicit cplinfo(const string &c="", const string &r="", const string &v="", const string &f="") : code(c), res(r), var(v), ref(f) {} bool islval() const { return var!="" || ref!=""; } }; typedef map mss; class ITR { public: typedef std::list::iterator kid; typedef std::list::reverse_iterator reverse_kid; typedef std::list::const_iterator const_kid; struct itrinfo{ string filename; int linenumber; string name; ITR * ref; itrinfo(): linenumber(0), ref(0) {} explicit itrinfo(kid i){ *this = (*i)->getinfo(); } itrinfo(const string &f, int ln, const string &s="") : filename(f), linenumber(ln), name(s), ref(0) {} }; protected: itrinfo inf; std::list children; ITR * parent; ITR(const itrinfo &i): inf(i), parent(0) {} private: ITR(const ITR&); void operator=(const ITR&); public: virtual ~ITR()=0; itrinfo getinfo() const { return inf; } string getname() const { return inf.name; } string fullname() const; int children_size() const { return children.size(); } void addkid(ITR* p); void addkids(ITR* p, ITR* q){ addkid(p); addkid(q); } ITR* getParent(){ return parent; } void setParent(ITR* p){ parent=p; } void setRef(ITR* p){ inf.ref = p; } void erasekids(kid from, kid to); void dropkids(){ children.clear(); } void dropkid(int idx); void insertkid(kid where, ITR * what); string dump(int ind=0) const; virtual string typname() const { return "UNKNOWN"; } virtual cplinfo compile(int) { throw errinfo()+" Undefined compile in '"+typname()+"' object"; } virtual string init_eval() { throw errinfo()+" Undefined init_eval in '"+typname()+"' object"; } ITR* child(int n) const; ItrRoot* getRoot(); ItrFunc* getFunc(); string errinfo() const; void unbind(Context&c); }; class ItrChar: public ITR { public: ItrChar(const itrinfo &i): ITR(i) {} ItrChar(const string &f, int ln, char x) : ITR( itrinfo(f, ln, string()+x) ) {} string typname() const { return "Char"; } string printchar() const; bool isspace() const; bool isalnum() const; bool isstrlit() const; static bool isoctal(kid i); static bool ishex(kid i); static int gethex(kid i); }; /** 3.3.2 ITR goodies **/ bool isString(ITR::kid i); bool isConst(ITR* i); inline bool isConst(ITR::kid i){ return isConst(*i); } bool isBool(ITR* i); inline bool isBool(ITR::kid i){ return isBool(*i); } bool isStk(ITR* i); bool isVar(ITR* i); bool isLab(ITR* i); bool isId(ITR* i); inline bool isId(ITR::kid i){ return isId(*i); } bool isChar(ITR* i); inline bool isChar(ITR::kid i){ return isChar(*i); } bool isSymbol(ITR::kid i, const string &s); bool isKeyword(ITR::kid i, const string &s); void constEval(ITR** p); void multEval(ITR** p); void Warning(const string&); void addBoolKid(ITR* parent, ITR * bkid, ITR::itrinfo ifo); void addIntKid(ITR* parent, ITR * ikid, ITR::itrinfo ifo); inline string err(ITR::kid i){ return (*i)->errinfo(); } inline string name(ITR::kid i){ return (*i)->getname(); } inline ITR::itrinfo info(ITR::kid i){ return (*i)->getinfo(); } /** 3.3.3 ITR derived classes **/ /** 3.3.3.1 ITR root **/ class ItrRoot: public ITR { kid tokenize_word(kid i); kid tokenize_symbol(kid i); kid tokenize_comment(kid i); kid tokenize_strlit(kid i); kid tokenize_strlit_esc(kid i, char &); public: ItrRoot(): ITR(itrinfo()) {} ItrRoot(const string& filename, const string& filetext); string execute(); cplinfo compile(int); void preprocess(); void tokenize(); void parse(Context &c); void merge(ItrRoot& a); string typname() const { return "Root"; } }; /** 3.3.3.2 Constants and variables, primaries **/ class ItrConst: public ITR { public: ItrConst(const itrinfo &i): ITR(i) {} cplinfo compile(int); string typname() const { return "Const"; } string init_eval(){ return getval(); } string getval() const; }; class ItrId: public ITR { public: ItrId(const itrinfo &i): ITR(i) {} string typname() const { return "Id"; } }; class ItrVar: public ITR { public: ItrVar(const itrinfo &i): ITR(i) {} string typname() const { return "Variable"; } cplinfo compile(int); void setValue(const string&); string getValue(); string init_eval(); }; class ItrStk: public ITR { int bp_index; public: ItrStk(const itrinfo &i, int bpi): ITR(i), bp_index(bpi) {} string typname() const { return "Stackvar:"+ut::i2a(bp_index); } int get_bpi() const { return bp_index; } ITR * itrrepr(itrinfo i); }; class ItrLab: public ITR { public: ItrLab(const itrinfo &i): ITR(i) {} string typname() const { return "Label"; } cplinfo compile(int); string init_eval(); }; class ItrKeyword: public ITR { public: ItrKeyword(const itrinfo &i): ITR(i) {} ItrKeyword(const string &s): ITR(itrinfo("",0,s)) {} string typname() const { return "Keyword"; } }; class ItrSymbol: public ITR { public: ItrSymbol(const itrinfo &i): ITR(i) {} string typname() const { return "Symbol"; } }; class ItrString: public ITR { public: ItrString(const itrinfo &i): ITR(i) {} string typname() const { return "String"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); string init_eval(); string getval(); int size(){ return inf.name.size(); } }; /** 3.3.3.3 Imperatives **/ class ItrFunc: public ITR { int stk_sz; public: ItrFunc(const itrinfo &i, int ss): ITR(i), stk_sz(ss) {} string typname() const { return "Function:"+ut::i2a(stk_sz); } cplinfo compile(int); string compile_head(); string compile_tail(); static parseinfo parse(kid i, Context &c); }; class ItrBlock: public ITR { public: ItrBlock(const itrinfo &i): ITR(i) {} string typname() const { return "Block"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c, bool newscope); }; class ItrStatement: public ITR { public: ItrStatement(const itrinfo &i): ITR(i) {} string typname() const { return "Statement"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); }; class ItrKeyStatement: public ITR { public: ItrKeyStatement(const itrinfo &i): ITR(i) {} string typname() const { return "Keyword-statement"; } string break_lab, cont_lab; cplinfo compile(int); cplinfo compile_return(); cplinfo compile_goto(); cplinfo compile_if(); cplinfo compile_while(); cplinfo compile_for(); cplinfo compile_brcont(); static parseinfo parse(kid i, Context &c); static parseinfo parse_for(kid i, Context &c); static parseinfo parse_break(kid i, Context &c); static parseinfo parse_while(kid i, Context &c); static parseinfo parse_if(kid i, Context &c); static parseinfo parse_continue(kid i, Context &c); static parseinfo parse_goto(kid i, Context &c); }; class ItrLabStatement: public ITR { public: ItrLabStatement(const itrinfo &i): ITR(i) {} string typname() const { return "Label-statement"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); }; /** 3.3.3.4 Declarations **/ class ItrDeclaration: public ITR { public: ItrDeclaration(const itrinfo &i): ITR(i) {} string typname() const { return "Declaration"; } cplinfo compile(int); cplinfo compile_glob(); cplinfo compile_local(); static parseinfo parse(kid i, Context &c); void initialize(); }; class ItrTypeName: public ITR { public: ItrTypeName(const itrinfo &i): ITR(i) {} string typname() const { return "Typename"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); }; class ItrDeclarator: public ITR { public: ItrDeclarator(const itrinfo &i): ITR(i) {} string typname() const { return "Declarator"; } cplinfo compile(int); string compile_local(); static parseinfo parse(kid i, Context &c); static parseinfo parse_extern(kid i, Context &c); static parseinfo parse_stk(kid i, Context &c); void initialize(); }; class ItrParamTypeList: public ITR { public: ItrParamTypeList(const itrinfo &i): ITR(i) {} string typname() const { return "Param-type-list"; } static parseinfo parse(kid i, Context &c); void addVars(Context &c); vector getNames(); }; /** 3.3.3.5 Expressions **/ class ItrExpr: public ITR { public: ItrExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Expression"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; class ItrOpio: public ITR { public: ItrOpio(const itrinfo &i): ITR(i) {} string typname() const { return "OperatorIO"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); }; class ItrAssExpr: public ITR { public: ItrAssExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Assignment"; } cplinfo compile(int); cplinfo compile_var_all(int, const cplinfo &left, const cplinfo &right, string mycode); cplinfo compile_var_eq(int, const cplinfo &left, const cplinfo &right); cplinfo compile_var_sub(int, const cplinfo &left, const cplinfo &right); cplinfo compile_var_add(int, const cplinfo &left, const cplinfo &right); cplinfo compile_ref_all(int, const cplinfo &left, const cplinfo &right, string mycode); cplinfo compile_ref_eq(int, const cplinfo &left, const cplinfo &right); cplinfo compile_ref_sub(int, const cplinfo &left, const cplinfo &right); cplinfo compile_ref_add(int, const cplinfo &left, const cplinfo &right); static parseinfo parse(kid i, Context &c); }; class ItrEqualExpr: public ITR { public: ItrEqualExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Equality"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; class ItrUnarExpr: public ITR { public: ItrUnarExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Unary"; } cplinfo compile(int); cplinfo compile_var(int, const cplinfo &in); cplinfo compile_ref(int, const cplinfo &in); static parseinfo parse(kid i, Context &c); string init_eval(); }; class ItrAssOperator: public ITR { public: ItrAssOperator(const itrinfo &i): ITR(i) {} string typname() const { return "Assignment-op"; } static parseinfo parse_intl(kid i); }; class ItrPostExpr: public ITR { public: ItrPostExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Postfix"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); cplinfo compile_func_call(int cmd); cplinfo compile_incdec(int cmd); string compile_func_lab(); string compile_func_expr(); string compile_func_noret(int sz); pair compile_func_retval(int sz); }; class ItrExprList: public ITR { public: ItrExprList(const itrinfo &i): ITR(i) {} string typname() const { return "Expression-list"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); }; class ItrPrimExpr: public ITR { public: ItrPrimExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Primiry"; } static parseinfo parse(kid i, Context &c); }; class ItrRelExpr: public ITR { public: ItrRelExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Relational"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; class ItrAddExpr: public ITR { public: ItrAddExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Additive"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); string init_eval(); }; class ItrMulExpr: public ITR { public: ItrMulExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Multiplicative"; } static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; class ItrCondExpr: public ITR { public: ItrCondExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Conditional"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; class ItrLogOrExpr: public ITR { public: ItrLogOrExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Logical-Or"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; class ItrLogAndExpr: public ITR { public: ItrLogAndExpr(const itrinfo &i): ITR(i) {} string typname() const { return "Logical-And"; } cplinfo compile(int); static parseinfo parse(kid i, Context &c); static parseinfo parse(parseinfo, Context &c); }; /** 3.3.4 Library manager declarations **/ namespace lib { string load(const string& filename); void process(ItrRoot & program, vector& names, vector& texts); void dumplib(); } //lib } // hsqcomp /** 3.4 Emulator **/ namespace emulator { struct Memi { vector v; int & operator[](int i) { if( i<0 ) { throw "Access violation: "+ut::i2a(i); } if( i>=int(v.size()) ) v.resize(i+1,0); return v[i]; } int size(){ return v.size(); } }; struct Memb { vector v; big::inumber & operator[](const big::inumber & i) { register int x = i.toint(); if( x<0 ) { throw "Access violation: "+i.str(); } if( x>=int(v.size()) ) v.resize(x+1,0); return v[x]; } int size(){ return v.size(); } }; } //emulartor /** 3.5 Compiler **/ /** 3.6 Parser **/ namespace hsqcomp{ class Context { public: enum vartype { VAR, LAB, STK }; struct ref { ITR* itr; vartype typ; int idx; ref(ITR*i,vartype t, int x=0): itr(i), typ(t), idx(x) {} ref(): itr(0), typ(LAB), idx(0) {} }; typedef map scope; private: list vars; list unres; // cannot be std::set (undeterministic order) void resolve(const string&, ITR *); int bp_index; // watch swap public: Context(){} ~Context(){} void addUnres(ITR *i); void addVar(const string&, vartype var, ITR *); bool getVar(const string&, vartype * var, ITR** =0); bool getVarTop(const string&, vartype * var, ITR** =0); void unbind(ITR*); ITR * extract1(); int size() const { return vars.size(); } string dump(); void swap(Context&c); void push_scope(){ vars.push_front(scope()); } void pop_scope(){ vars.pop_front(); } void reset_bp(){ bp_index=1; } int get_bp(int d=1); }; inline int Context::get_bp(int d) { int bpo=bp_index; bp_index+=d; return bpo; } inline void Context::swap(Context&c) { vars.swap(c.vars); unres.swap(c.unres); std::swap(bp_index,c.bp_index); } } // hsqcomp /** 4 Bignum implementation **/ namespace big{ /** 4.1 GCD **/ number gcd(number y, number x) { if( x>y ) x.swap(y); if( x==0 ) return y; number k; for(;;) { k = y%x; if( k==0 ) return x; x.swap(y); x.swap(k); } } /** 4.2 Number **/ bool number::operator==(const number &n) const { if( x.size() != n.x.size() ) return false; for( int i=0; i<(int)x.size(); i++ ) if( x[i] != n.x[i] ) return false; return true; } number::number(int n) { x.push_back(n); comb(); } void number::comb() { for( int i=0; i<(int)x.size(); i++ ) if( x[i] >= G ) { int n = x[i]/G; x[i] %= G; ac(i+1) += n; } for( int i=(int)x.size()-1; i>=0; i-- ) if( x[i]==0 ) x.pop_back(); else break; } number & number::operator-=(const number &n) { if( *this0; i-- ) { x[i]-=1; x[i-1] += G; } for( int i=0; i<(int)x.size(); i++ ) x[i] -= n.at(i); comb(); return *this; } number::number(const string &s) { number r; for( unsigned i=0; i'9' ) continue; r *= 10; r += s[i]-'0'; } x.swap(r.x); } bool number::operator<(const number &n) const { if( x.size() < n.x.size() ) return true; if( x.size() > n.x.size() ) return false; for( int i=x.size()-1; i>=0; i-- ) if( at(i) < n.at(i) ) return true; else if( at(i) > n.at(i) ) return false; return false; } bool number::operator>(const number &n) const { if( x.size() > n.x.size() ) return true; if( x.size() < n.x.size() ) return false; for( int i=x.size()-1; i>=0; i-- ) if( at(i) > n.at(i) ) return true; else if( at(i) < n.at(i) ) return false; return false; } void number::divMod(const number &n, number * divisor) { number &r=*this, u(n); int i=0; if( divisor ) *divisor = 0; if( r==u ) { x.clear(); if( divisor ) *divisor = 1; return; } while( r>u ) { u.shift(1); ++i; } while(i) { u.shift(-1); i--; while( r>=u ) { r-=u; if( divisor ) *divisor += number(1).shift(i); } } return; } number & number::operator%=(const number &n) { number &r=*this, u(n); int i=0; if( r==u ) { x.clear(); return r; } while( r>u ) { u.shift(1); ++i; } while(i) { u.shift(-1); i--; while( r>=u ) r-=u; } return r; } number & number::shift(int k) { if( k==0 || x.size()==0 ) return *this; if( k<0 && -k>=(int)x.size() ) { x.clear(); return *this; } if( k>0 ) { for( int i=x.size()-1; i>=-k; i-- ) ac(i+k)=at(i); } if( k<0 ) { for( int i=0; i<(int)x.size(); i++ ) ac(i)=at(i-k); comb(); } return *this; } number & number::operator+=(const number &n) { int sz = x.size()>n.x.size()?x.size():n.x.size(); for( int i=0; i< sz; i++ ) ac(i) += n.at(i); comb(); return *this; } number & number::operator*=(const number &n) { number r; for( int i=0; i<(int)n.x.size(); i++ ) { number rr(*this); for( int j=0; j<(int)rr.x.size(); j++ ) rr.x[j] *= n.at(i); rr.comb(); rr.shift(i); r += rr; } swap(r); comb(); return *this; } string number::str(unsigned pad) const { string r; if( x.size()<1 ) { r = "0"; } else { char b[20]; for( int i=0; i<(int)x.size(); i++ ) { std::sprintf(b,"%.3d",x[i]); r = string(b)+r; } while( r.size() && (r[0]=='0' || r[0]==',' )) r.erase(0,1); } if( pad ) while( r.size() < pad ) r = "0" + r; return r; } int number::toint() const { int r=0; for( int i=(int)x.size()-1; i>=0; i-- ) { r = r*G+at(i); } return r; } /** 4.3 Rebasing **/ vector rebase(number n, int base) { vector r; number m; while ( n>0 ) { m=n; m.divMod(base,&n); r.push_back(m.toint()); } return r; } number rebase(vector v, int base) { number r; if( v.empty() ) return r; unsigned i = v.size()-1; r = v[i]; while(i--) { r *= base; r += v[i]; } return r; } /** 4.4 Integer **/ bool inumber::operator<(const inumber &x) const { if( neg && x.neg ) return n>x.n; if( neg && !x.neg ) return true; if( !neg && x.neg ) return false; return n(const inumber &x) const { return x<*this; } bool inumber::operator==(const inumber &x) const { if( neg != x.neg ) return false; return n==x.n; } int inumber::toint() const { int r = n.toint(); return neg?-r:r; } inumber inumber::operator-() const { inumber r(*this); r.neg = !r.neg; return r; } inumber & inumber::operator+=(const inumber &b) { /* 1 ++ a+b 2 +- a-b 3 -+ b-a 4 -- -(a+b) */ if( neg == b.neg ){ n+=b.n; return *this; } if( !neg && b.neg ){ *this -= -b; return *this; } inumber &a = *this; inumber t(a); a = b; a -= -t; return a; } inumber & inumber::operator-=(const inumber &b) { /* 1 ++ a>=b a-b a= b ){ n-=b.n; return *this; } number t(n); n = b.n; n -= t; neg = true; return *this; } if( !neg && b.neg ) return *this += -b; if( neg && !b.neg ) { n+=b.n; return *this; } inumber t(*this); *this = -b; *this -= -t; return *this; } inumber::inumber(int i) : neg(false) { if( i>=0 ){ n=number(i); return; } neg = true; n = number(-i); } inumber::inumber(string s) : neg(false) { if( s.size() && s[0]=='-' ) { neg = true; n = number(s.substr(1)); }else n = number(s); } string inumber::str() const { return neg?"-"+n.str():n.str(); } } //big /** 5 Utility implementation **/ namespace ut{ string logtag_function(const char* file, int line) { string r = file; replaceAll(r,".cpp","@"); replaceAll(r,".inc","@"); replaceAll(r,".h","/"); //r += i2a(line); r = i2a(line); return "{"+r+"}"; } string i2a(int x) { std::ostringstream os; os<'~' ) r[i]='.'; return r; } int sign(string *s) { if( !s->size() || (*s)[0]!='-' ) return 1; s->erase(0,1); return -1; } string str_mult(const string &x, const string &y) { string nx(x), ny(y); int sx = sign(&nx); int sy = sign(&ny); big::number a(nx), b(ny); a*=b; if( sx!=sy && a!=0 ) return "-"+a.str(); return a.str(); } bool str_eq(const string &x, const string &y) { string nx(x), ny(y); int sx = sign(&nx); int sy = sign(&ny); if( sx!=sy ) return false; big::number a(nx), b(ny); return a==b; } string str_add(const string &x, const string &y) { string nx(x), ny(y); int sx = sign(&nx); int sy = sign(&ny); if( sx==1 && sy==-1 ) return str_sub(nx,ny); if( sx==-1 && sy==1 ) return str_sub(ny,nx); big::number a(nx), b(ny); if( sx==1 && sy==1 ) return (a+=b).str(); a+=b; if( a!=0 ) return "-"+a.str(); return a.str(); } string str_sub(const string &x, const string &y) { string nx(x), ny(y); int sx = sign(&nx); int sy = sign(&ny); if( sx==1 && sy==-1 ) return str_add(nx,ny); if( sx==-1 && sy==-1 ) return str_sub(ny,nx); big::number a(nx), b(ny); if( sx==1 && sy==1 ) { if( a>=b ) return (a-=b).str(); return "-"+(b-=a).str(); } a+=b; if( a!=0 ) return "-"+a.str(); return a.str(); } string str_div(const string &x, const string &y) { string nx(x), ny(y); int sx = sign(&nx); int sy = sign(&ny); big::number a(nx), b(ny), c; if( b==0 ) throw string()+"division by 0"; a.divMod(b,&c); if( sx!=sy && c!=0 ) return "-"+c.str(); return c.str(); } string str_mod(const string &x, const string &y) { string nx(x), ny(y); int sx = sign(&nx); int sy = sign(&ny); big::number a(nx), b(ny), c; if( b==0 ) throw string()+"division by 0"; a.divMod(b,&c); if( sx!=sy && a!=0 ) return "-"+a.str(); return a.str(); } } // ut /** 6 Emulator **/ namespace emulator{ void sqemulateb(vector &vtext) { Memb mem; big::inumber ip=0; for( size_t i=0; i>s; if( !in ) break; mem[ip++] = big::inumber(s); } } vtext.clear(); ip=0; for(;;) { big::inumber a = mem[ip++]; big::inumber b = mem[ip++]; if( ip>=mem.size() ) throw "Incomplete instruction: "+ip.str(); big::inumber c = mem[ip++]; if( a == -1 && b==-1 ) { char ch; std::cin.get(ch); if(std::cin) cout< &vtext) { Memi mem; int ip=0; for( size_t i=0; i>s; if( !in ) break; mem[ip++] = ut::a2i(s); } } vtext.clear(); ip=0; for(;;) { int a = mem[ip++]; int b = mem[ip++]; if( ip>=mem.size() ) throw "Incomplete instruction: "+ut::i2a(ip); int c = mem[ip++]; if( a == -1 && b==-1 ) { char ch; std::cin.get(ch); if(std::cin) cout< &vtext, bool bign) { if( !bign ) sqemulatei(vtext); else sqemulateb(vtext); } } // emulate /** 7 Assembly compiler **/ namespace asqcomp{ /* grammar program := list of intructions intruction := [.] list of items ( ';' | '\n' ) item := ( [label:]expression | [label:][[number]] ) label := id expression := ( term | term+expression | term-expression ) term := ( -term | (expression) | const | id ) const := ( number | 'letter' | ? ) */ struct item { int addr; string s; big::inumber i; enum { EMPTY, STR, RES } state; item() : i(0), state(EMPTY) {} string dump(bool=false); }; string item::dump(bool extra) { string r; if( extra ) r = ut::i2a(addr)+":"; if( state==RES ) return r+i.str(); return r+ "#" +s; } struct instruction { vector items; string dump(bool=false); }; string instruction::dump(bool extra) { string r; for( size_t i=0; i lab2adr; string prog; typedef string::size_type sint; sint pip = 0; int line=1; int addr = 0; map unres; void eat() { while( pip 0"; j=c.i.toint()+2; pip = mpip; } if ( --j == 1 ) { item c; ++pip; getconst(c); ++pip; j=0; return false; } i.i = 0; i.state = item::RES; return true; } bool getStr(item &i) { static int j=0; if( j==0 ) j++; // start if( pip+j >=prog.size() ) throw "Sqasm: "+ut::i2a(line)+" string not closed"; if( prog[pip+j] == '"' ) // end { pip+=j+1; j=0; return false; } { int p0 = pip; pip += j-1; i.i = (unsigned char)getChr(); j+=pip-j+1-p0; pip=p0; } i.state = item::RES; return true; } bool getitem(item &i) { begin: eat(); if( prog[pip] == '\n' ) { pip++; line++; return false; } if( prog[pip] == ';' ) { pip++; return false; } if( pip>=prog.size() ) return false; string lab; while( getlabel(lab) ) { if( lab2adr.find(lab) == lab2adr.end() ) lab2adr[lab] = addr; else throw "Sqasm: "+ut::i2a(line)+": label "+lab+" was defined"; lab=""; } eat(); i.addr = addr++; if( prog[pip] == '"' ) { if( getStr(i) ) return true; addr--; // finished with string - try again goto begin; } if( prog[pip] == '[' ) { if( getArray(i) ) return true; addr--; // finished with array - try again goto begin; } getexpr(i); return true; } bool getinstr(instruction &i) { eatn(); bool data = false; if( prog[pip] == '.' ) { data = true; pip++; } while( pip100000 ) throw string()+"Sqasm (I): instruction size hardcoded limit exceeded." " This is an artificial limit added for security purposes." " Remove the limit inside the compiler if necessary."; } if( i.items.size() == 0 ) return false; if( i.items.size() == 1 ) { item &k = i.items.front(); if( k.state==item::STR && k.s=="" ) return false; } if( !data && i.items.size() == 1 ) { item k = i.items.front(); k.addr = addr++; i.items.push_back(k); } if( !data && i.items.size() == 2 ) { item k; k.addr = addr++; k.i = addr; k.state = item::RES; i.items.push_back(k); } return true; } vector program() { vector r; while( pip100000 ) throw string()+"Sqasm (P): instructions hardcoded limit exceeded." " This is an artificial limit added for security purposes." " Remove the limit inside the compiler if necessary."; } return r; } void resolve(item &i) { if( i.state==item::EMPTY ) throw string()+"Sqasm: Internal Error: empty item"; if( i.state==item::RES ) return; prog = i.s; pip=0; item k; getitem(k); if( k.state==item::RES ) { i.state = item::RES; i.i = k.i; return; } i.s = k.s; unres[i.s] = i.addr; } void resolve(instruction &n) { for( size_t i=0; i &pr) { for( size_t i=0; i &vtext) { for( size_t i=0; i pr = program(); string r; for( size_t i=0; i::iterator i=unres.begin(); i!=unres.end(); i++ ) r += " {" + i->first + ":" + ut::i2a(i->second) + "}"; throw r; } prog = ""; return r; } } // asqcomp /** 8 HSQ compiler **/ namespace hsqcomp{ using namespace ut; /** 8.1 Itr dump **/ string itrcompile(vector &vname, vector &vtext) { ItrRoot program; lib::process(program,vname,vtext); return program.dump(0); } /** 8.2 General hsq functions **/ ItrRoot::ItrRoot(const string& file, const string& text): ITR(itrinfo()) { inf.filename = file; int line = 1; for( size_t i=0; iparent ) { throw LT+"internal - parent set"; } p->parent=this; } void ITR::insertkid(kid where, ITR * what) { children.insert(where,what); if( what->parent ) throw LT+"internal - parent set"; what->parent = this; } void ITR::erasekids(kid from, kid to) { for( kid j=from; j!=to; ++j ) delete *j; children.erase(from,to); } std::string ITR::dump(int ind) const { string r; for( int i=0; igetname()+":"+i2a(inf.ref->getinfo().linenumber); r += "\n"; for( const_kid i=children.begin(); i!=children.end(); ++i ) r += (*i)->dump(ind+3); return r; } bool iskeyword(const string &s) { static char *kws[] = { "auto", "enum", "restrict", "unsigned", "break", "extern", "return", "void", "case", "float", "short", "volatile", "char", "for", "signed", "while", "const", "goto", "sizeof", "_Bool", "continue", "if", "static", "_Complex", "default", "inline", "struct", "_Imaginary", "do", "int", "switch", "__out", "double", "long", "typedef", "__in", "else", "register", "union", "__asm" }; const int sz = sizeof(kws)/sizeof(kws[0]); for( int i=0; i='a' ) return true; if( c<='Z' && c>='A' ) return true; if( c<='9' && c>='0' ) return true; if( c=='_' ) return true; return false; } bool ItrChar::isstrlit() const { if( inf.name.empty() ) return false; char c = inf.name[0]; if( c=='\'' || c=='\"' ) return true; return false; } string ItrChar::printchar() const { if( inf.name.empty() ) return ""; char c = inf.name[0]; string r; if( c>31 && c<127 ) r+=c; else r+=i2a((unsigned char)c); return r; } void ItrRoot::merge(ItrRoot& a) { for( kid i=a.children.begin(); i!=a.children.end(); ++i ) (*i)->setParent(this); children.splice(children.end(), a.children); if( inf.filename=="" ) inf.filename = a.inf.filename; if( inf.linenumber==0 ) inf.linenumber = a.inf.linenumber; } ITR::kid ItrRoot::tokenize_comment(kid i) { kid j=i; string str; ItrChar * c1 = dynamic_cast(*i); if( c1==0 ) throw LT+"internal error: empty symbol"; ItrChar * c2 = 0; if( ++i != children.end() ) c2 = dynamic_cast(*i); if( !c2 ) throw LT+"internal error: empty symbol"; if( c2->getname()=="/" ) { while( i!=children.end() && (*i)->getname() != "\n" ) ++i; goto cut; } if( c2->getname()=="*" ) { if( ++i == children.end() ) goto cut; if( ++i == children.end() ) goto cut; while( i!=children.end() ) { if( (*i++)->getname() != "*" ) continue; if( (*i)->getname() == "/" ){ ++i; goto cut; } } throw LT+err(j)+" EOF in comment"; } cut: children.erase(j,i); return i; } ITR::kid ItrRoot::tokenize_symbol(kid i) { kid j=i; string str; itrinfo ifo = (*i)->getinfo(); ItrChar * c1 = dynamic_cast(*i); if( c1==0 ) throw string("internal error: empty symbol"); ItrChar * c2 = 0; if( ++i != children.end() ) c2 = dynamic_cast(*i); if( c2 ) { str += c1->getname(); str += c2->getname(); if( str == "//" || str == "/*" ) return tokenize_comment(j); if( str == "==" || str == "!=" || str == "++" || str == "--" || str == "+=" || str == "-=" || str == "||" || str == "&&" || str == "<=" || str == ">=" || str == "*=" || str == "/=" || str == "%=" ) { itrinfo ifo = c1->getinfo(); ifo.name = str; insertkid(++i, new ItrSymbol(ifo) ); delete c1; delete c2; children.erase(j,--i); return i; } } str = c1->getname(); if( str=="{" || str=="(" || str==")" || str==";" || str=="}" || str=="," || str=="+" || str=="*" || str==":" || str=="-" || str=="[" || str=="]" || str=="#" || str=="<" || str==">" || str=="?" || str=="'" || str=="\"" || str=="!" || str=="/" || str=="%" || str=="=" || str=="&" ) { insertkid(i, new ItrSymbol(c1->getinfo()) ); delete c1; children.erase(j); return i; } throw LT+(*i)->errinfo()+" Unknown symbol '"+c1->printchar()+"'"; } ITR::kid ItrRoot::tokenize_word(kid i) { kid j=i; string str; itrinfo ifo = (*i)->getinfo(); for(;;) { ItrChar * c = dynamic_cast(*i); if( c==0 ) break; if( i==children.end() ) break; if( !c->isalnum() ) break; str += c->getname(); delete *i; ++i; if( i==children.end() ) break; } children.erase(j,i); if( str.empty() ) throw string("internal error: empty word"); ifo.name = str; if( std::isdigit(str[0]) ) insertkid(i,new ItrConst(ifo)); else if( iskeyword(str) ) insertkid(i,new ItrKeyword(ifo)); else insertkid(i,new ItrId(ifo)); return i; } ITR::kid ItrRoot::tokenize_strlit_esc(kid i, char &c) { kid j=i; if( name(i) != "\\" ) return j; if( ++i == children.end() ) return j; if( name(i) == "'" ){ c='\''; return ++i; } if( name(i) == "\"" ){ c='\"'; return ++i; } if( name(i) == "?" ){ c='\?'; return ++i; } if( name(i) == "\\" ){ c='\\'; return ++i; } if( name(i) == "a" ){ c='\a'; return ++i; } if( name(i) == "b" ){ c='\b'; return ++i; } if( name(i) == "f" ){ c='\f'; return ++i; } if( name(i) == "n" ){ c='\n'; return ++i; } if( name(i) == "r" ){ c='\r'; return ++i; } if( name(i) == "t" ){ c='\t'; return ++i; } if( name(i) == "v" ){ c='\v'; return ++i; } if( ItrChar::isoctal(i) ) { int a = ItrChar::gethex(i); if( ++i == children.end() ) return j; if( ItrChar::isoctal(i) ) { a = 8*a+ItrChar::gethex(i); if( ++i == children.end() ) return j; if( ItrChar::isoctal(i) ) a = 8*a+ItrChar::gethex(i++); if( i == children.end() ) return j; } c = char(a); return i; } if( name(i) == "x" ) { int a=0; if( ++i == children.end() ) return j; if( ItrChar::ishex(i) ) a = ItrChar::gethex(i); else throw LT + err(i) + " bad hex sequence"; if( ++i == children.end() ) return j; if( ItrChar::ishex(i) ) a = 16*a+ItrChar::gethex(i++); if( i == children.end() ) return j; c = char(a); return i; } throw LT + err(i) + " unknown escape sequence"; } ITR::kid ItrRoot::tokenize_strlit(kid i) { kid j=i; string str; string nm = name(i); itrinfo ifo = (*i)->getinfo(); if( nm!="\'" && nm!="\"" ) throw LT; ++i; for(;;) { if( i==children.end() ) throw LT+err(j)+" End-of-File in string literal"; char c; kid n = tokenize_strlit_esc(i,c); if( n!=i ) { i=n; str+=c; continue; } if( name(i)=="\n" ) throw LT+err(j)+" new line in string literal"; if( name(i)==nm ) break; str += name(i); ++i; } ++i; children.erase(j,i); if( nm=="\'" ) { ifo.name = nm+str+nm; insertkid(i,new ItrConst(ifo)); } else { ifo.name = str; insertkid(i,new ItrString(ifo)); } return i; } void ItrRoot::tokenize() { itrinfo eof; for( kid j,i=children.begin(); i!=children.end(); ) { eof = info(i); ItrChar * c = dynamic_cast(*i); if( c==0 ){ ++i; continue; } if( c->isspace() ) { j=i; ++i; delete *j; children.erase(j); continue; } if( c->isalnum() ) i = tokenize_word(i); else if( c->isstrlit() ) i = tokenize_strlit(i); else i = tokenize_symbol(i); } eof.name = "EOF"; addkid(new ItrChar(eof)); addkid(new ItrChar(eof)); addkid(new ItrChar(eof)); addkid(new ItrChar(eof)); } string ITR::errinfo() const { return "("+inf.filename+":"+i2a(inf.linenumber)+")"; } ITR* ITR::child(int n) const { for( const_kid i=children.begin(); i!=children.end(); ++i ) if( n-- == 0 ) return *i; throw LT+"internal error: children out of boudaries"; } void ITR::dropkid(int n) { for( kid i=children.begin(); i!=children.end(); ++i ) if( n-- == 0 ) { (*i)->setParent(0); children.erase(i); return; } throw LT+"internal error: children out of boudaries"; } ItrRoot* ITR::getRoot() { ITR *p = this; while( p->parent ) p=p->parent; ItrRoot* r = dynamic_cast(p); if( !r ) throw string()+"internal: root object is not Root"; return r; } ItrFunc* ITR::getFunc() { ITR *p = this; for(;;) { ItrFunc* s = dynamic_cast(p); if( s ) return s; p=p->parent; if( !p ) throw LT+" internal: function object not found"; } } string ITR::fullname() const { return (parent?parent->fullname():string()) + "." + getname()+":"+i2a(getinfo().linenumber); } bool isSymbol(ITR::kid i, const string &s) { ItrSymbol* sym = dynamic_cast(*i); return ( sym && sym->getname() == s ); } bool isKeyword(ITR::kid i, const string &s) { ItrKeyword* kw = dynamic_cast(*i); return ( kw && kw->getname() == s ); } bool isConst(ITR * i) { return 0!=dynamic_cast(i); } bool isBool(ITR * i) { /* ! unary ! < > <= >= relation == != equality && || and or */ if( dynamic_cast(i) && i->getname()=="!" ) return true; if( dynamic_cast(i) ) return true; if( dynamic_cast(i) ) return true; if( dynamic_cast(i) ) return true; if( dynamic_cast(i) ) return true; return false; } bool isId(ITR* i) { return 0!=dynamic_cast(i); } bool isChar(ITR* i) { return 0!=dynamic_cast(i); } bool isVar(ITR* i) { return 0!=dynamic_cast(i); } bool isStk(ITR* i) { return 0!=dynamic_cast(i); } bool isLab(ITR* i) { return 0!=dynamic_cast(i); } bool isString(ITR::kid i) { return 0!=dynamic_cast(*i); } void ItrVar::setValue(const string&){ throw LT; } string ItrVar::getValue(){ throw LT; } void ItrRoot::preprocess() { kid j=children.begin(); for( kid i=j; i!=children.end(); ) { ItrSymbol * c = dynamic_cast(*i); if( c==0 || c->getname() != "#" ){ j=i; ++i; continue; } int line = (*i)->getinfo().linenumber; if( i!=j && (*j)->getinfo().linenumber == line ) throw LT+err(i)+" # directive must start at the beginning of the line"; j=i; while( (*i)->getinfo().linenumber == line ) ++i; Warning(LT+err(j)+" # directive not yet implemented - ignored"); erasekids(j,i); } } bool ItrChar::isoctal(kid i) { ItrChar * c = dynamic_cast(*i); if( !c ) throw LT; string n = name(i); if( n.size() != 1 ) throw LT; if( n[0] >= '0' && n[0] <= '7' ) return true; return false; } bool ItrChar::ishex(kid i) { ItrChar * c = dynamic_cast(*i); if( !c ) throw LT; string n = name(i); if( n.size() != 1 ) throw LT; if( n[0] >= '0' && n[0] <= '9' ) return true; if( n[0] >= 'a' && n[0] <= 'f' ) return true; if( n[0] >= 'A' && n[0] <= 'F' ) return true; return false; } int ItrChar::gethex(kid i) { ItrChar * c = dynamic_cast(*i); if( !c ) throw LT; string n = name(i); if( n.size() != 1 ) throw LT; if( n[0] >= '0' && n[0] <= '9' ) return n[0]-'0'; if( n[0] >= 'a' && n[0] <= 'f' ) return n[0]-'a'+10; if( n[0] >= 'A' && n[0] <= 'F' ) return n[0]-'A'+10; throw LT; } string ItrConst::getval() const { string n = getname(); if( n.size() == 3 && n[0] == '\'' && n[2] == '\'' ) return i2a( int( (unsigned char)(n[1]) ) ); return n; } void Context::addUnres(ITR *p) { list::iterator i = std::find(unres.begin(), unres.end(), p); if( i == unres.end() ) unres.push_back(p); } void Context::unbind(ITR * p) { list::iterator i = std::find(unres.begin(), unres.end(), p); if( i!=unres.end() ) unres.erase(i); } void ITR::unbind(Context & c) { c.unbind(this); for( kid i=children.begin(); i!=children.end(); ++i ) (*i)->unbind(c); } ITR * Context::extract1() { if( unres.empty() ) return 0; ITR * r = *unres.begin(); unres.erase(unres.begin()); return r; } /** 8.3 Lib manager **/ namespace lib{ map library; void initlibrary(); void appenditr(ItrRoot & program, const string &name, const string &text, Context &c) { ItrRoot unit(name,text); unit.tokenize(); unit.preprocess(); unit.parse(c); program.merge(unit); } void warn(set & unres) { for( set::iterator i=unres.begin(); i!=unres.end(); ++i ) hsqcomp::Warning(LT+(*i)->errinfo()+" unresolved '"+(*i)->getname()+"'"); } void process(ItrRoot & program, vector &vname, vector &vtext) { initlibrary(); set unres; Context c; c.push_scope(); for( size_t i=0; i::iterator i = library.find(u->getname()); if( i == library.end() ) unres.insert(u); else { appenditr(program,"::"+u->getname(),i->second,c); } } warn(unres); c.pop_scope(); } void dumplib() { initlibrary(); std::ofstream of("library.dump"); for( map::iterator i=library.begin(); i!=library.end(); ++i ) { of<<"// --- "<first<<" --- //\n"; of<second<<'\n'; } } void initlibrary() { library["putchar"] = "int putchar(int x)\n" "{\n" " return __out x;\n" "}\n"; library["_putint"] = "int _putintr(int x);\n" "int _putint(int x)\n" "{\n" " if( x<0 )\n" " {\n" " __out 45;\n" " return 1+_putintr(-x);\n" " }\n" " if( x>0 )\n" " return _putintr(x);\n" "\n" " __out 48;\n" " return 1;\n" "}\n"; library["_putintr"] = "int _divMod(int a, int b, int m);\n" "int _putintr(int x)\n" "{\n" " if( x>0 )\n" " {\n" " int i,j;\n" " i = _divMod(x,10,&j);\n" " i =_putintr(i);\n" " __out 48+j;\n" " return i+1;\n" " }\n" " return 0;\n" "}\n"; library["_divMod"] = "int _divMod(int a, int b, int j)\n" "{\n" " if( a0 ) return k;\n" " return -k;\n" "}\n"; library["_multr"] = "int _divMod(int a, int b, int m);\n" "int _multr(int a , int b)\n" "{\n" " if( b<1 ) return 0;\n" " if( b<2 ) return a;\n" " int i,j,k=0;\n" " i = _divMod(b,2,&j);\n" "\n" " if( j<1 ) ; else k=a;\n" " return _multr(a+a,i) + k;\n" "}\n"; library["_div"] = "int _divMod(int a, int b, int m);\n" "int _div(int a , int b)\n" "{\n" " int s=1, j;\n" " if( a<0 ){ a=-a; s=-s; }\n" " if( b<0 ){ b=-b; s=-s; }\n" " if( b<1 ) return 0;\n" " int k = _divMod(a,b,&j);\n" " if( s>0 ) return k;\n" " return -k;\n" "}\n"; library["_mod"] = "int _divMod(int a, int b, int m);\n" "int _mod(int a , int b)\n" "{\n" " int s=1, j=0;\n" " if( a<0 ){ a=-a; s=-s; }\n" " if( b<0 ){ b=-b; s=-s; }\n" " if( b<1 ) return 0;\n" " _divMod(a,b,&j);\n" " if( s>0 ) return j;\n" " return -j;\n" "}\n"; library["getchar"] = "int getchar()\n" "{\n" " return __in;\n" "}\n"; library["puts"] = "int puts(int s)\n" "{\n" " int p=s;\n" " while(*s) __out *s++;\n" " return s-p;\n" "}\n"; library["printf"] = "int puts(int s);\n" "int _putint(int i);\n" "int printf(int s)\n" "{\n" " int k=0;\n" " for( int i=0; ++k,*s; s++ )\n" " {\n" " if( *s != '%' ){ __out *s; continue; }\n" " ++s;\n" " if( *s == '%' ) __out '%';\n" " else if( *s == 'c' ) __out *(&s-++i);\n" " else if( *s == 's' ) --k+=puts(*(&s-++i));\n" " else if( *s == 'd' ) --k+=_putint(*(&s-++i));\n" " }\n" " return --k;\n" "}\n"; } } // lib /** 8.4 Compiler **/ /** 8.4.1 General classes and utilities **/ const bool COMM = false; const string DEC = "_"; class Temp { int tempTable, tempTableMax; vector usage; vector released; public: Temp(): tempTable(0), tempTableMax(0) {} string writeTempTable(); void reset(); string get(); void resetUsage(){ usage.clear(); } string dump(); string pusher(); string popper(); void release(const string& s); }; class Compiler { map constTable; int labTable; public: string getConst(const string &c); string getLab(); Temp temp; bool func_has_return; string writeMain(); string writeHeader(); string writeConstTable(); string writeRegisters(); Compiler(): labTable(0), func_has_return(false) {} static string push_clear(); static string push_sub(const string &a); static string push_add(const string &a); static string pushm(const string &a); static string pushp(const string &a); static string popm(const string &a); static cplinfo deref(string code, string res); static string genlabname(ITR *i); static string callmain(); } compiler; string Temp::get() { string t; if( !released.empty() ) { t = released.back(); released.pop_back(); } else t = "t"+i2a(++tempTable); vector::iterator i = std::find(usage.begin(),usage.end(),t); if( i == usage.end() ) usage.push_back(t); return t; } void Temp::reset() { if( tempTableMaxgetFunc(); if( !f ) throw LT; r += DEC+f->getname()+DEC+i->getname(); return r; } string Compiler::getLab() { return "l"+i2a(++labTable); } string Compiler::pushm(const string &a) { string comm = COMM?"\t# push (neg) "+a+"\n":string(); return comm + push_clear() + push_sub(a); } string Compiler::pushp(const string &a) { string comm = COMM?"\t# push (pos) "+a+"\n":string(); return comm + push_clear() + push_add(a); } string Compiler::getConst(const std::string &c) { map::iterator cl = constTable.find(c); if( cl != constTable.end() ) return cl->second; if( c=="1" ) return "dec"; if( c=="-1" ) return "inc"; static int idx = 0; string name = "c"+i2a(++idx); constTable[c] = name; return name; } string Compiler::callmain() { string r; r += Compiler::push_clear(); r += "\t?+6; sp ?+2; ?+2 0 ?+1; . ?+3; Z Z "+DEC; r += "main"; r += "; inc sp\n\n"; return r; } string Temp::pusher() { string r; for( size_t i=0; i::iterator i = std::find(released.begin(),released.end(),s); if( i!=released.end() ) throw LT + s; released.push_back(s); } string hsqcompile(vector &vname, vector &vtext) { if( vtext.empty() ) return ""; ItrRoot program; lib::process(program,vname,vtext); return program.compile(0).code; } /** 8.4.2 Compile functions **/ /** 8.4.2.1 Low IO **/ cplinfo ItrOpio::compile(int cmd) { if( getname()=="__out" ) { if( children_size() != 1 ) throw LT; cplinfo ex = child(0)->compile(1); if( cmd==0 ) { compiler.temp.release(ex.res); return cplinfo(ex.code+"\t"+ex.res+" (-1)\n"); } if( cmd==1 ) return cplinfo(ex.code+"\t"+ex.res+" (-1)\n",ex.res); if( cmd==2 ) throw LT+errinfo()+" not l-value"; } if( getname()=="__in" ) { if( children_size() != 0 ) throw LT; if( cmd==0 ) return cplinfo(""); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd!=1 ) throw LT; string t = compiler.temp.get(); string code = "\t$t; (-1) $t\n"; replaceAll(code,"$t",t); return cplinfo(code,t); } throw LT+getname(); } /** 8.4.2.2 Declaration **/ cplinfo ItrDeclaration::compile(int) { if( children_size() < 2 ) throw LT; if( getname() == "extern" ) return cplinfo(""); if( parent == getRoot() ) return compile_glob(); return compile_local(); } cplinfo ItrDeclaration::compile_local() { string r; kid i = children.begin(); ++i; // skip type for( ; i!=children.end(); ++i ) { ItrDeclarator * dtr = dynamic_cast(*i); if( dtr ) { r += dtr->compile_local(); continue; } throw LT+errinfo()+ (*i)->typname(); } return cplinfo(r); } cplinfo ItrDeclaration::compile_glob() { string r; r += ". "; kid i = children.begin(); ++i; // skip type for( ; i!=children.end(); ++i ) { r += " "; ItrDeclarator * dtr = dynamic_cast(*i); if( dtr ) { r += dtr->compile(0).code; continue; } throw LT+errinfo()+ (*i)->typname(); } return cplinfo(r+"\n\n"); } /** 8.4.2.3 Declarator **/ cplinfo ItrDeclarator::compile(int) { if( getname()=="=" ) { if( children_size()!=2 ) throw LT; ItrId * id = dynamic_cast(child(0)); if( !id ) throw LT; string r = child(1)->init_eval(); r = DEC + id->getname() + ":" + r; return cplinfo(r); } if( getname()=="0" ) { if( children_size()!=1 ) throw LT; ItrId * id = dynamic_cast(child(0)); if( !id ) throw LT; string r = DEC + id->getname() + ":0"; return cplinfo(r); } if( getname()=="[" ) { if( children_size()!=2 ) throw LT; ItrId * id = dynamic_cast(child(0)); if( !id ) throw LT; string r = child(1)->init_eval(); r = DEC + id->getname() + ":[" + r + "]"; return cplinfo(r); } if( getname()=="\"" ) { if( children_size()!=2 ) throw LT; ItrId * id = dynamic_cast(child(0)); if( !id ) throw LT; ItrString * str = dynamic_cast(child(1)); if( !str ) throw LT; string r = DEC + id->getname() + ":"+str->getval(); return cplinfo(r); } throw LT; } string ItrDeclarator::compile_local() { if( getname()=="=" ) { if( children_size()!=2 ) throw LT; ItrStk * id = dynamic_cast(child(0)); if( !id ) throw LT; ITR * id_rep = id->itrrepr(getinfo()); ItrAssExpr * ass = new ItrAssExpr(getinfo()); ITR * ex = child(1); dropkid(1); ass->addkids(id_rep,ex); cplinfo cpl = ass->compile(0); // restore kid ass->dropkid(1); addkid(ex); delete ass; return cpl.code; } if( getname()=="0" ) return ""; if( getname()=="[" ) return ""; if( getname()=="\"" ) { throw LT+errinfo() +" string initialization on stack variables " "not implemented"; } if( getname()=="{" ) { throw LT+errinfo() +" array initialization on stack variables " "not implemented"; } throw LT; } /** 8.4.2.4 Function **/ cplinfo ItrFunc::compile(int) { if( children_size() == 2 ) return cplinfo(""); if( children_size() != 3 ) throw LT; string r; // write label r += DEC+getname()+":\n"; // compile block - function body compiler.func_has_return = false; compiler.temp.resetUsage(); string body = child(2)->compile(0).code; // must compile body first, because head uses size of pushed temps r += compile_head(); r += body; r += compile_tail(); return cplinfo(r); } string ItrFunc::compile_head() { string r; r += compiler.pushm("bp"); r += "\tbp; sp bp\n"; if( stk_sz ) { string nsz = i2a(stk_sz); string s = compiler.getConst(nsz); r += "\t$sz sp\n"; replaceAll(r,"$sz",s); } r += compiler.temp.pusher(); return r+"\n"; } string ItrFunc::compile_tail() { string r; if( compiler.func_has_return ) r += "end_"+getname()+":\n"; r += compiler.temp.popper(); r += "\tsp; bp sp\n"; r += compiler.popm("bp"); r += "\t?+8; sp ?+4; ?+7; 0 ?+3; Z Z 0\n\n"; return r; } /** 8.4.2.5 Constant evaluator **/ string ItrString::init_eval() { return compiler.getConst(getval()); } string ItrUnarExpr::init_eval() { if( getname() == "&" ) { if( children_size()!=1 ) throw LT; ITR * id = child(0); if( !isVar(id) && !isLab(id) ) goto err; return DEC+id->getname(); } err: throw LT+errinfo()+" not static expression in initializer"; } string ItrAddExpr::init_eval() { if( getname() == "+" || getname() == "-" ) { if( children_size()!=2 ) throw LT; return "(" +child(0)->init_eval() +getname() +child(1)->init_eval() +")"; } throw LT + getname(); } string ItrVar::init_eval() { throw LT+errinfo()+" not static expression in initializer"; } string ItrLab::init_eval() { return DEC+getname(); } /** 8.4.2.6 Unary Expression **/ cplinfo ItrUnarExpr::compile(int cmd) { if( children_size()!=1 ) throw LT; if( getname() == "+" ) { return child(0)->compile(cmd); } if( getname() == "-" ) { if( cmd > 1 ) throw LT+errinfo()+ " -() is not l-value"; cplinfo ex = child(0)->compile(1); if( ex.res == "" ) throw LT; if( cmd==0 ) return cplinfo(ex.code); string t = compiler.temp.get(); string r = "\t$t; $e $t\n"; replaceAll(r,"$e",ex.res); replaceAll(r,"$t",t); compiler.temp.release(ex.res); return cplinfo(ex.code+r,t); } if( getname() == "++" || getname() == "--" ) { cplinfo ex = child(0)->compile(2); if( ex.var!="" ) return compile_var(cmd,ex); if( ex.ref!="" ) return compile_ref(cmd,ex); throw LT+errinfo()+" not l-value"; } if( getname() == "*" ) { cplinfo ex = child(0)->compile(1); if( ex.res == "" ) throw LT; if( cmd==2 ) return cplinfo(ex.code,"","",ex.res); if( cmd==0 ) return cplinfo(ex.code); return compiler.deref(ex.code,ex.res); } if( getname() == "&" ) { ITR * c = child(0); ItrUnarExpr * ue = dynamic_cast(c); if( ue && ue->getname()=="*" ) { if( ue->children_size()!=1 ) throw LT; return ue->child(0)->compile(1); } if( isLab(c) ) return c->compile(1); if( isVar(c) ) { string n = DEC+c->getname(); string cc = compiler.getConst(n); return cplinfo("",cc); } if( isStk(c) ) throw LT+errinfo()+ getname()+" internal error"; cplinfo r = c->compile(2); return cplinfo(r.code,r.ref); } if( getname() == "!" ) { /* [!x] t; x t; inc t */ if( cmd==0 ) return child(0)->compile(0); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd != 1 ) throw LT; cplinfo ex = child(0)->compile(1); string t = compiler.temp.get(); compiler.temp.release(ex.res); string code = "\t$t; $x $t; inc $t\n"; replaceAll(code,"$t",t); replaceAll(code,"$x",ex.res); return cplinfo(ex.code+code,t); } throw LT+errinfo()+ getname()+" please implement me"; } cplinfo ItrUnarExpr::compile_var(int cmd, const cplinfo &ex) { string code; if( getname()=="++" ) code = "\tinc $x\n"; else if( getname()=="--" ) code = "\tdec $x\n"; else throw LT; replaceAll(code,"$x",ex.var); code = ex.code + code; if( cmd==0 ) return cplinfo(code); if( cmd==1 ) return cplinfo(code,ex.var); if( cmd==2 ) return cplinfo(code,"",ex.var); throw LT; } cplinfo ItrUnarExpr::compile_ref(int cmd, const cplinfo &ref_and_code) { if( children_size()!=1 ) throw LT; string ac; if( getname() == "++" ) ac = "inc"; else if( getname() == "--" ) ac = "dec"; else throw LT; const cplinfo & ex = ref_and_code; if( ex.ref!="" ) { string comm = COMM?"\t# pre inc/dec\n":""; string code = "\t$x Z; ?+9; Z ?+5; Z; $ac 0\n"; replaceAll(code,"$x",ex.ref); replaceAll(code,"$ac",ac); if( cmd==0 ) { code = ex.code + comm + code; compiler.temp.release(ex.ref); return cplinfo(code); } if( cmd==1 ) { code = ex.code + comm + code; return compiler.deref(code,ex.ref); } if( cmd==2 ) { code = ex.code + comm + code; return cplinfo(code,"","",ex.ref); } throw LT; } throw LT; } /** 8.4.2.7 Variable **/ cplinfo ItrVar::compile(int cmd) { string n = getname(); if( n.empty() ) throw LT; if( n[0] != '@' ) n = DEC+n; else n = n.substr(1); if( cmd == 0 ) return cplinfo(""); if( cmd == 1 ) return cplinfo("",n); if( cmd == 2 ) return cplinfo("","",n); throw LT; } /** 8.4.2.8 Assignment Expression **/ cplinfo ItrAssExpr::compile(int cmd) { if( children_size() != 2 ) throw LT; cplinfo right = child(1)->compile(1); cplinfo left = child(0)->compile(2); if( left.var!="" ) { if( getname() == "=" ) return compile_var_eq(cmd,left,right); if( getname() == "-=" ) return compile_var_sub(cmd,left,right); if( getname() == "+=" ) return compile_var_add(cmd,left,right); throw LT+errinfo()+" operator '"+getname()+"' is not supported"; } if( left.ref!="" ) { if( getname() == "=" ) return compile_ref_eq(cmd,left,right); if( getname() == "-=" ) return compile_ref_sub(cmd,left,right); if( getname() == "+=" ) return compile_ref_add(cmd,left,right); throw LT+errinfo()+" operator '"+getname()+"' is not supported"; } throw LT+errinfo()+" not constant expression as l-value"; } cplinfo ItrAssExpr::compile_ref_all (int cmd, const cplinfo &left, const cplinfo &right, string mycode) { /* [*k a] */ // order important string code = right.code + left.code; replaceAll(mycode,"$1",left.ref); replaceAll(mycode,"$2",right.res); if( cmd==0 ) { compiler.temp.release(left.ref); compiler.temp.release(right.res); return cplinfo(code+mycode); } if( cmd==1 ) { compiler.temp.release(left.ref); return cplinfo(code+mycode,right.res); } if( cmd==2 ) { compiler.temp.release(right.res); return cplinfo(code+mycode,"","",left.ref); } throw LT; } cplinfo ItrAssExpr::compile_ref_eq (int cmd, const cplinfo &left, const cplinfo &right) { /* [*k=a] t1; t2; t3 ?+8*3-1; ?+7*3; ?+8*3 k Z; Z t1; Z t2; Z t3; Z ?+4*3-2; ?+3*3-1 ?+4*3-1 t1:0 t2:0 a Z; Z t3:0; Z */ string mycode = "\t?+23; ?+21; ?+24; $1 Z; Z ?+10; Z ?+8\n" "\tZ ?+11; Z; 0; $2 Z; Z 0; Z\n"; return compile_ref_all(cmd,left,right,mycode); } cplinfo ItrAssExpr::compile_ref_sub (int cmd, const cplinfo &left, const cplinfo &right) { /* [*k-=a] t ?+4*3 k Z; Z t; Z ?+2*3-1 a t:0 */ string mycode = "\t?+12; $1 Z; Z ?+5; Z; $2 0\n"; return compile_ref_all(cmd,left,right,mycode); } cplinfo ItrAssExpr::compile_ref_add (int cmd, const cplinfo &left, const cplinfo &right) { /* [*k+=a] t ?+5*3 k Z; Z t; Z ?+3*3-1 a Z; Z t:0; Z */ string mycode = "\t?+15; $1 Z; Z ?+8; Z\n" "\t$2 Z; Z 0; Z\n"; return compile_ref_all(cmd,left,right,mycode); } cplinfo ItrAssExpr::compile_var_all (int cmd, const cplinfo &left, const cplinfo &right, string mycode) { /* [k a] */ // order important string code = right.code + left.code; replaceAll(mycode,"$k",left.var); replaceAll(mycode,"$a",right.res); code+=mycode; if( cmd==0 ) return cplinfo(code); if( cmd==1 ) return cplinfo(code,right.res); if( cmd==2 ) return cplinfo(code,"",left.var); throw LT; } cplinfo ItrAssExpr::compile_var_sub (int cmd, const cplinfo &left, const cplinfo &right) { /* [k-=a] a k */ string mycode = "\t$a $k\n"; return compile_var_all(cmd,left,right,mycode); } cplinfo ItrAssExpr::compile_var_add (int cmd, const cplinfo &left, const cplinfo &right) { /* [k+=a] a Z; Z k; Z */ string mycode = "\t$a Z; Z $k; Z\n"; return compile_var_all(cmd,left,right,mycode); } cplinfo ItrAssExpr::compile_var_eq (int cmd, const cplinfo &left, const cplinfo &right) { /* [k=a] k; a Z; Z k; Z */ string mycode = "\t$k; $a Z; Z $k; Z\n"; if( left.var==right.res ) mycode = ""; return compile_var_all(cmd,left,right,mycode); } cplinfo ItrAddExpr::compile(int cmd) { if( children_size() != 2 ) throw LT; cplinfo a = child(0)->compile(1); cplinfo b = child(1)->compile(1); string code = a.code + b.code; if( cmd==0 ) return cplinfo(code); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd!=1 ) throw LT; if( getname()=="+" ) { /* [a+b] t1; t2 a t1; b t1; t1 t2 */ string t1 = compiler.temp.get(); string t2 = compiler.temp.get(); string mycode = "\t$t1; $t2; $a $t1; $b $t1; $t1 $t2\n"; replaceAll(mycode,"$t1",t1); replaceAll(mycode,"$t2",t2); replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); compiler.temp.release(a.res); compiler.temp.release(b.res); compiler.temp.release(t1); return cplinfo(code+mycode,t2); } if( getname()=="-" ) { /* [a-b] t; a Z; Z t; Z b t; */ string t = compiler.temp.get(); string mycode = "\t$t; $a Z; Z $t; Z; $b $t\n"; replaceAll(mycode,"$t",t); replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); compiler.temp.release(a.res); compiler.temp.release(b.res); return cplinfo(code+mycode,t); } throw LT; } /** 8.4.2.9 Constant **/ cplinfo ItrConst::compile(int cmd) { if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd==0 ) return cplinfo(""); string n = getval(); string c = compiler.getConst(n); return cplinfo("",c); } /** 8.4.2.10 Label **/ cplinfo ItrLab::compile(int cmd) { if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd==0 ) return cplinfo(""); if( !inf.ref ) throw LT; if ( dynamic_cast(inf.ref) ) { string n = compiler.genlabname(this); string c = compiler.getConst(n); return cplinfo("",c); } string n = DEC+getname(); string c = compiler.getConst(n); return cplinfo("",c); } /** 8.4.2.11 Root **/ cplinfo ItrRoot::compile(int) { string r; r += compiler.writeHeader(); for( kid i=children.begin(); i!=children.end(); ++i ) r += (*i)->compile(0).code; r += compiler.writeMain(); r += compiler.writeConstTable(); r += compiler.temp.writeTempTable(); r += compiler.writeRegisters(); return cplinfo(r); } string Compiler::writeHeader() { return "\ttop:top top sqmain\n\n"; } string Compiler::writeMain() { string r; r += "sqmain:\n"; r += Compiler::callmain(); r += "\tZ Z (-1)\n\n"; return r; } string Compiler::writeConstTable() { map &ct = constTable; if( ct.empty() ) return ""; string r; r += "."; for( map::iterator i=ct.begin(); i!=ct.end(); ++i ) { r += " " + i->second +":"+i->first; } r += "\n\n"; return r; } string Temp::writeTempTable() { if( !tempTableMax ) return ""; string r; r += "."; reset(); for( int i=1; i<=tempTableMax; ++i ) r += " t" + i2a(i) + ":0"; r += "\n\n"; return r; } string Compiler::writeRegisters() { return ". inc:-1 Z:0 dec:1 ax:0 bp:0 sp:-sp\n"; } /** 8.4.2.12 Block **/ cplinfo ItrBlock::compile(int) { string r; for( kid i=children.begin(); i!=children.end(); ++i ) { string c = (*i)->compile(0).code; compiler.temp.reset(); if( c!="" ) r += c + "\n"; } return cplinfo(r); } /** 8.4.2.13 String **/ cplinfo ItrString::compile(int cmd) { if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd==0 ) return cplinfo(""); string c = compiler.getConst(getval()); return cplinfo("", compiler.getConst(c) ); } string ItrString::getval() { string r; string s = getname(); for( string::size_type i=0; icompile(2); if( ex.var!="" && cmd == 0 ) { /* inc/dec k */ string code = "\t"+ac+" "+ex.var+"\n"; return cplinfo(ex.code+code); } if( ex.var!="" && cmd == 1 ) { /* k->t; inc/dec k */ string t = compiler.temp.get(); string code = "\t$t; $k Z; Z $t; Z; $ac $k\n"; replaceAll(code,"$t",t); replaceAll(code,"$k",ex.var); replaceAll(code,"$ac",ac); return cplinfo(ex.code+code,t); } if( ex.ref!="" ) { string comm = COMM?"\t# post inc/dec\n":""; string code = "\t$x Z; ?+9; Z ?+5; Z; $ac 0\n"; replaceAll(code,"$x",ex.ref); replaceAll(code,"$ac",ac); if( cmd==0 ) { code = ex.code + comm + code; compiler.temp.release(ex.ref); return cplinfo(code); } if( cmd==1 ) { cplinfo der = compiler.deref(ex.code,ex.ref); code = der.code + comm + code; return cplinfo(code,der.res); } throw LT; } throw LT; } cplinfo ItrPostExpr::compile_func_call(int cmd) { if( getname() != "(" ) throw LT; if( cmd==2 ) throw LT+errinfo()+" not l-value"; cplinfo args; int nargs = 0; if( children_size() == 2 ) { args = child(1)->compile(0); nargs = child(1)->children_size(); } else if( children_size() != 1 ) throw LT; string call; if( isLab(child(0)) ) call = compile_func_lab(); else call = compile_func_expr(); string noret = compile_func_noret(nargs); pair retval = compile_func_retval(nargs); string code = args.code + call; if( cmd==0 ) return cplinfo( code + noret ); if( cmd==1 ) return cplinfo( code + retval.first, retval.second ); if( cmd==2 ) throw LT+errinfo()+" not l-value"; throw LT; } string ItrPostExpr::compile_func_lab() { /* t1 ?+6 sp t1 ?+2 t2 t1:0 @ ---+ ?+2 0 ?+1 . t2:@ ----+ | ?+3 Z Z lab <--|-+ <---+ */ string lab = DEC+child(0)->getname(); string comm = COMM?"\t# function call: "+lab+"\n":string(); return comm + Compiler::push_clear() +"\t?+6; sp ?+2; ?+2 0 ?+1; . ?+3; Z Z "+lab+"\n"; } string ItrPostExpr::compile_func_expr() { /* [x()] t1 ?+6 sp t1 ?+2 t2 t1:0 @ --+ ?+2 0 ?+1 . t2:@ -----|-+ ?+12 t3 <----+ | ?+10 x Z | Z t3 | ?+3 Z Z t3:0 | <------+ */ cplinfo x = child(0)->compile(1); string comm = COMM?"\t# functional function call\n":""; compiler.temp.release(x.res); string code = "\t?+6; sp ?+2; ?+2 0 ?+1; . ?+12\n" "\t?+10; $x Z; Z ?+3; Z Z 0\n"; replaceAll(code,"$x",x.res); return comm + Compiler::push_clear() + x.code + code; } string ItrPostExpr::compile_func_noret(int i) { string cval = i2a(-(i+1)); string cname = compiler.getConst(cval); return "\t"+cname+" sp\n"; } pair ItrPostExpr::compile_func_retval(int i) { string t= compiler.temp.get(); string code = "\t$t; ax $t\n"; replaceAll(code,"$t",t); code += compile_func_noret(i); return pair(code,t); } /** 8.4.2.16 Expression List **/ cplinfo ItrExprList::compile(int) { cplinfo ret; for( reverse_kid i=children.rbegin(); i!=children.rend(); ++i ) { cplinfo ci = (*i)->compile(1); ret.code += ci.code; ret.code += Compiler::pushp(ci.res); compiler.temp.release(ci.res); } return ret; } /** 8.4.2.17 Keyword Statement **/ /** 8.4.2.17.1 Top function **/ cplinfo ItrKeyStatement::compile(int) { if( getname() == "return" ) return compile_return(); if( getname() == "goto" ) return compile_goto(); if( getname() == "if" ) return compile_if(); if( getname() == "while" ) return compile_while(); if( getname() == "for" ) return compile_for(); if( getname() == "continue" ) return compile_brcont(); if( getname() == "break" ) return compile_brcont(); throw LT+errinfo()+" keyword statement '"+getname()+"' not yet implemented"; } /** 8.4.2.17.2 break, continue **/ cplinfo ItrKeyStatement::compile_brcont() { ITR * p = this; ItrKeyStatement * loop; while(p) { loop = dynamic_cast(p); if( loop ) if( loop->getname()=="for" || loop->getname()=="while" ) break; p = p->getParent(); } loop = dynamic_cast(p); if( !loop ) throw LT+errinfo()+" '"+getname() +"' statement is not enclosed in any loop"; string lab = (getname() == "break")? loop->break_lab : loop->cont_lab; if( lab == "" ) throw LT+loop->getname()+":"+getname(); string code = "\tZ Z "+lab+"\n\n"; return cplinfo(code); } /** 8.4.2.17.3 if **/ cplinfo ItrKeyStatement::compile_if() { /* if(k){...} if(k){...}else{...} 1 Z k skip1 Z k skip1 {...} {...} 2 3 skip1: Z Z skip2 skip1: {...} 4 skip2: */ if( children_size() < 2 ) throw LT; if( children_size() > 3 ) throw LT; bool iselse = ( children_size() == 3 ); cplinfo st = child(1)->compile(0); cplinfo st2; if( iselse ) st2 = child(2)->compile(0); cplinfo ex = child(0)->compile(1); compiler.temp.release(ex.res); string skip1 = compiler.getLab(); string skip2 = ( iselse ? compiler.getLab() : string() ); string comm_if = COMM?"\t# if\n":""; string comm_ifc = COMM?"\t# if: code\n":""; string comm_ex = COMM?"\t# if: expr\n":""; string comm_st1 = COMM?"\t# if: st1\n":""; string comm_st2 = COMM?"\t# if: st2\n":""; string code1 = "\tZ $k $skip1\n"; string code2 = skip1+":\n"; string code3 = "\tZ Z " + skip2 + "\n" + code2; string code4 = skip2+":\n"; replaceAll(code1,"$k",ex.res); replaceAll(code1,"$skip1",skip1); string code = comm_if + comm_ex + ex.code + comm_ifc + code1 + comm_st1 + st.code; if( !iselse ) code += code2; else code += code3 + comm_st2 + st2.code + code4; return cplinfo(code); } /** 8.4.2.17.4 for **/ cplinfo ItrKeyStatement::compile_for() { /* [ for( st1 ex1; ex2 ) st2 ] 1 2 begin: 3 4 Z x skip 5 6 cont: 7 8 Z Z begin skip: */ if( children_size() != 4 ) throw LT; string begin = compiler.getLab(); cont_lab = compiler.getLab(); string skip = compiler.getLab(); break_lab = skip; cplinfo st1 = child(0)->compile(0); cplinfo ex1 = child(1)->compile(1); cplinfo ex2 = child(2)->compile(0); cplinfo st2 = child(3)->compile(0); compiler.temp.release(ex1.res); string code1 = st1.code; string code2 = begin+":\n"; string code3 = ex1.code; string code4 = "\tZ $x $skip\n"; string code5 = st2.code; string code6 = cont_lab+":\n"; string code7 = ex2.code; string code8 = "\tZ Z "+begin+"\n"+skip+":\n"; replaceAll(code4,"$x",ex1.res); replaceAll(code4,"$skip",skip); string code = code1 + code2 + code3 + code4 + code5 + code6 + code7 + code8; return cplinfo(code); } /** 8.4.2.17.5 while **/ cplinfo ItrKeyStatement::compile_while() { /* while(x){...} 0 begin: 1 Z x skip {...} 2 Z Z begin skip: */ if( children_size() != 2 ) throw LT; string begin = compiler.getLab(); string skip = compiler.getLab(); cont_lab = begin; break_lab = skip; cplinfo st = child(1)->compile(0); cplinfo ex = child(0)->compile(1); compiler.temp.release(ex.res); string comm_wh = COMM?"\t# while\n":""; string comm_whc = COMM?"\t# while: code\n":""; string comm_ex = COMM?"\t# while: expr\n":""; string comm_st = COMM?"\t# while: st\n":""; string code0 = begin+":\n"; string code1 = "\tZ $x $skip\n"; string code2 = "\tZ Z "+begin+"\n"+skip+":\n"; replaceAll(code1,"$x",ex.res); replaceAll(code1,"$skip",skip); string code = comm_wh + code0 + comm_ex + ex.code + comm_whc + code1 + comm_st + st.code + code2; return cplinfo(code); } /** 8.4.2.17.6 goto **/ cplinfo ItrKeyStatement::compile_goto() { if( children_size()!=1 ) throw LT; if( isLab(child(0)) ) { string nm = Compiler::genlabname(child(0)); string code = "\tZ Z "+nm+ "\n"; return cplinfo(code); } /* t ?+10 x Z Z t ?+3 Z Z t:0 */ cplinfo x = child(0)->compile(1); compiler.temp.release(x.res); string code = "\t?+10; $x Z; Z ?+3; Z Z 0\n"; replaceAll(code,"$x",x.res); return cplinfo(x.code + code); } /** 8.4.2.17.7 return **/ cplinfo ItrKeyStatement::compile_return() { if( getname() != "return" ) throw LT; if( children_size() > 1 ) throw LT; compiler.func_has_return = true; string r; cplinfo ex; if( children_size() == 1 ) { ex = child(0)->compile(1); r = "\tax; $t ax\n"; replaceAll(r,"$t",ex.res); r = ex.code + r; } ItrFunc * func = getFunc(); if( !func ) throw LT; r += "\tZ Z end_" + func->getname() + "\n"; return cplinfo(r); } /** 8.4.2.18 Expression **/ cplinfo ItrExpr::compile(int cmd) { if( getname()=="," ) { if( children_size() != 2 ) throw LT; cplinfo ex1 = child(0)->compile(0); cplinfo ex2 = child(1)->compile(cmd); ex2.code = ex1.code + ex2.code; return ex2; } throw LT + "["+getname()+"]"; } /** 8.4.2.19 Labeled Statement **/ cplinfo ItrLabStatement::compile(int) { if( children_size() != 1 ) throw LT; cplinfo st = child(0)->compile(0); string nm = Compiler::genlabname(this); string code = nm+":\n"; st.code = code + st.code; return st; } /** 8.4.2.20 Relational Exression **/ cplinfo ItrRelExpr::compile(int cmd) { if( children_size() != 2 ) throw LT; cplinfo a = child(0)->compile(1); cplinfo b = child(1)->compile(1); string code = a.code + b.code; if( cmd==0 ) return cplinfo(code); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd!=1 ) throw LT; if( getname()=="<" || getname()==">" ) { string t = compiler.temp.get(); compiler.temp.release(a.res); compiler.temp.release(b.res); string mycode = "\t$t; $a Z; Z $t; Z; $b $t\n"; replaceAll(mycode,"$t",t); if( getname()==">" ) { replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); } else { replaceAll(mycode,"$a",b.res); replaceAll(mycode,"$b",a.res); } return cplinfo(code+mycode,t); } if( getname()=="<=" || getname()==">=" ) { /* [a>=b] a->t b t inc t */ string t = compiler.temp.get(); compiler.temp.release(a.res); compiler.temp.release(b.res); string mycode = "\t$t; $a Z; Z $t; Z; $b $t; inc $t\n"; replaceAll(mycode,"$t",t); if( getname()==">=" ) { replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); } else if( getname()=="<=" ) { replaceAll(mycode,"$a",b.res); replaceAll(mycode,"$b",a.res); } else throw LT; return cplinfo(code+mycode,t); } throw LT+getname(); } /** 8.4.2.21 Equality Expression **/ cplinfo ItrEqualExpr::compile(int cmd) { if( children_size() != 2 ) throw LT; cplinfo a = child(0)->compile(1); cplinfo b = child(1)->compile(1); string code = a.code + b.code; if( cmd==0 ) return cplinfo(code); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd!=1 ) throw LT; if( getname()=="==" && isConst(child(1)) && child(1)->getname()=="0" ) { /* t Z a ?+3 --+ +---- Z Z ?+9 | | +-- a Z ?+3 <-+ | | Z Z ?+3 --+ | +-> inc t | +---> <--+ */ string t = compiler.temp.get(); compiler.temp.release(a.res); compiler.temp.release(b.res); string mycode = "\t$t; Z $a ?+3; Z Z ?+9\n" "\t$a Z ?+3; Z Z ?+3; inc $t\n"; replaceAll(mycode,"$t",t); replaceAll(mycode,"$a",a.res); return cplinfo(code+mycode,t); } if( getname()=="==" ) { /* a->t b t ?+3 --+ +---- t t ?+9 | | +-- t Z ?+3 <-+ | | Z Z ?+3 --+ | +-> inc t | +---> <--+ */ string t = compiler.temp.get(); compiler.temp.release(a.res); compiler.temp.release(b.res); string mycode = "\t$t; $a Z; Z $t; Z; $b $t ?+3\n"; mycode += "\t$t $t ?+9; $t Z ?+3; Z Z ?+3; inc $t\n"; replaceAll(mycode,"$t",t); replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); return cplinfo(code+mycode,t); } if( getname()=="!=" && isConst(child(1)) && child(1)->getname()=="0" ) { /* t a Z +-- Z t @ ?+3 | Z Z @ ---+ ?+9 +-> Z | a t | a t | <-+ */ string t = compiler.temp.get(); compiler.temp.release(a.res); compiler.temp.release(b.res); string mycode = "\t$t; $a Z; Z $t ?+3; Z Z ?+9; Z; $a $t; $a $t\n"; replaceAll(mycode,"$t",t); replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); return cplinfo(code+mycode,t); } if( getname()=="!=" ) { /* t a Z Z t +-- b t @ +3 | Z Z @ --+ +15 +-> Z | t Z @ --+ +9 Z | t | inc t | <-+ */ string t = compiler.temp.get(); compiler.temp.release(a.res); compiler.temp.release(b.res); string mycode = "\t$t; $a Z; Z $t; $b $t ?+3; Z Z ?+15\n" "\tZ; $t Z ?+9; Z; $t; inc $t\n"; replaceAll(mycode,"$t",t); replaceAll(mycode,"$a",a.res); replaceAll(mycode,"$b",b.res); return cplinfo(code+mycode,t); } throw LT+getname(); } /** 8.4.2.22 Logical-And Expression **/ cplinfo ItrLogAndExpr::compile(int cmd) { /* [ a && b ] evaluate a if a false skip b return false if a true return evaluate b 1 2 t; Z a @ ---+ 3 | 4 Z b @ ---+ inc t | skip: | <-+ */ if( children_size() != 2 ) throw LT; cplinfo a = child(0)->compile(1); string t = compiler.temp.get(); cplinfo b = child(1)->compile(1); string skip = compiler.getLab(); string code2 = "\t$t; Z $a $skip\n"; string code4 = "\tZ $b $skip; inc $t;\n$skip:\n"; string code = a.code + code2 + b.code + code4; replaceAll(code,"$skip",skip); replaceAll(code,"$t",t); replaceAll(code,"$a",a.res); replaceAll(code,"$b",b.res); compiler.temp.release(a.res); compiler.temp.release(b.res); if( cmd==0 ) return cplinfo(code); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd!=1 ) throw LT; return cplinfo(code,t); } /** 8.4.2.23 Logical-Or Expression **/ cplinfo ItrLogOrExpr::compile(int cmd) { /* [ a || b ] evaluate a if a true skip b return true if a false return evaluate b 1 2 t; inc t; Z a ?+3 Z Z @ --+ 3 | 4 Z b ?+3 | Z Z @ --+ t | skip: | <-+ */ if( children_size() != 2 ) throw LT; cplinfo a = child(0)->compile(1); string t = compiler.temp.get(); cplinfo b = child(1)->compile(1); string skip = compiler.getLab(); string code2 = "\t$t; inc $t; Z $a ?+3; Z Z $skip\n"; string code4 = "\tZ $b ?+3; Z Z $skip; $t;\n$skip:\n"; string code = a.code + code2 + b.code + code4; replaceAll(code,"$skip",skip); replaceAll(code,"$t",t); replaceAll(code,"$a",a.res); replaceAll(code,"$b",b.res); compiler.temp.release(a.res); compiler.temp.release(b.res); if( cmd==0 ) return cplinfo(code); if( cmd==2 ) throw LT+errinfo()+" not l-value"; if( cmd!=1 ) throw LT; return cplinfo(code,t); } /** 8.4.2.24 Conditional Expression **/ cplinfo ItrCondExpr::compile(int cmd) { /* [ x ? a : b ] evaluate x if x true return evaluate a if x false return evaluate b cmd:0,1,2 1 2 Z x @ ------------+ 3 | 4a { a->t if res } | 4b { a->t if ref } | 4c { &a->t if var } | 5 Z Z @ ------------|-+ 6 skpa: | | 7 <-----------+ | 8a { a->t if res } | 8b { a->t if ref } | 8c { &a->t if var } | 9 next: <------------+ */ if( children_size() != 3 ) throw LT; cplinfo x = child(0)->compile(1); compiler.temp.release(x.res); string t = compiler.temp.get(); cplinfo a = child(1)->compile(cmd); cplinfo b = child(2)->compile(cmd); string skpa = compiler.getLab(); string next = compiler.getLab(); string co1 = x.code; string co2 = "\tZ "+ x.res + " " + skpa +"\n"; string co3 = a.code; string ctt = "\t$t; $p Z; Z $t; Z\n"; replaceAll(ctt,"$t",t); string co4; if( cmd==0 ){} else if( cmd==1 ) { co4 = ctt; replaceAll(co4,"$p",a.res); } else if( cmd==2 ) { if( a.ref!="") { co4 = ctt; replaceAll(co4,"$p",a.ref); } else if( a.var!="" ) { co4 = ctt; replaceAll(co4,"$p",compiler.getConst(a.var)); } else throw LT; } else throw LT; string co5 = "\tZ Z "+next+"\n"; string co6 = skpa+":\n"; string co7 = b.code; string co8; if( cmd==0 ){} else if( cmd==1 ) { co8 = ctt; replaceAll(co8,"$p",b.res); } else if( cmd==2 ) { if( b.ref!="") { co8 = ctt; replaceAll(co8,"$p",b.ref); } else if( b.var!="" ) { co8 = ctt; replaceAll(co8,"$p",compiler.getConst(b.var)); } else throw LT; } else throw LT; string co9 = next+":\n"; string co0 = COMM?"\t# conditional\n":""; string code = co1+co2+co3+co4+co5+co6+co7+co8+co9; if( a.res!="" ) compiler.temp.release(a.res); if( b.res!="" ) compiler.temp.release(b.res); if( a.ref!="" ) compiler.temp.release(a.ref); if( b.ref!="" ) compiler.temp.release(b.ref); if( cmd==0 ) return cplinfo(code); if( cmd==1 ) return cplinfo(code,t); if( cmd==2 ) return cplinfo(code,"","",t); throw LT; } /** 8.5 Static Evaluator **/ /** 8.5.1 Conditional expression **/ void constEval3(ITR** p) { ITR *& itr = *p; if( itr->children_size() != 3 ) throw LT+" internal: const evaluation"; ITR * o = itr; ItrConst * c0 = dynamic_cast(o->child(0)); if( !c0 ) return; ITR * c1 = o->child(1); ITR * c2 = o->child(2); itr->dropkids(); if( str_mult(c0->getval(),"1") == "0" ) { delete c0; delete c1; delete o; c2->setParent(0); itr = c2; return; } else { delete c0; delete c2; delete o; c1->setParent(0); itr = c1; return; } } /** 8.5.2 Pair expressions **/ void constEval2(ITR** p) { ITR *& itr = *p; if( itr->children_size() != 2 ) throw LT+" internal: const evaluation"; ITR * o = itr; ItrConst * c0 = dynamic_cast(o->child(0)); ItrConst * c1 = dynamic_cast(o->child(1)); if( !c0 ) return; if( !c1 ) return; ITR::itrinfo ifo = o->getinfo(); if( itr->getname() == "*" ) ifo.name = str_mult(c0->getval(),c1->getval()); else if( itr->getname() == "+" ) ifo.name = str_add(c0->getval(),c1->getval()); else if( itr->getname() == "-" ) ifo.name = str_sub(c0->getval(),c1->getval()); else if( itr->getname() == "/" ) ifo.name = str_div(c0->getval(),c1->getval()); else if( itr->getname() == "%" ) ifo.name = str_mod(c0->getval(),c1->getval()); else throw LT+" internal: const evaluation "+ifo.name; itr = new ItrConst(ifo); delete o; } /** 8.5.3 Array size **/ void constEvalArray(ITR** p) { ITR *& itr = *p; if( itr->children_size() != 2 ) throw LT; if( itr->getname() != "[" ) throw LT; ITR * c1 = itr->child(0); ITR * c2 = itr->child(1); ITR::itrinfo ifo = itr->getinfo(); ifo.name = "+"; ItrAddExpr * add = new ItrAddExpr(ifo); c1->setParent(0); c2->setParent(0); itr->dropkids(); add->addkids(c1,c2); ifo.name = "*"; ItrUnarExpr * ref = new ItrUnarExpr(ifo); ref->addkid(add); delete itr; itr = ref; } /** 8.5.4 Unary expressions **/ void constEval1(ITR** p) { ITR *& itr = *p; if( itr->children_size() != 1 ) throw LT+" internal: const evaluation"; ITR * o = itr; ITR * ic = o->child(0); ITR::itrinfo ifo = o->getinfo(); if( itr->getname() == "*" ) { ItrUnarExpr* uc = dynamic_cast(ic); if( uc && uc->getname() == "&" ) { ITR * c2 = uc->child(0); // itr -> o -> c/uc -> c2 ic->dropkids(); c2->setParent(0); itr = c2; delete o; } return; } if( itr->getname() == "&" ) { ItrUnarExpr* uc = dynamic_cast(ic); if( uc && uc->getname() == "*" ) { ITR * c2 = uc->child(0); // itr -> o -> c/uc -> c2 ic->dropkids(); c2->setParent(0); itr = c2; delete o; } return; } ItrConst * c = dynamic_cast(o->child(0)); if( !c && itr->getname() == "!" ) { ITR * c = itr->child(0); if( isBool(c) ) return; ITR::itrinfo ifo = itr->getinfo(); ifo.name = "=="; ItrEqualExpr * eq = new ItrEqualExpr(ifo); ifo.name = "0"; ItrConst * z = new ItrConst(ifo); c->setParent(0); itr->dropkids(); eq->addkids(c,z); delete itr; itr = eq; return; } if( !c ) return; if( itr->getname() == "+" ) { ifo.name = c->getval(); itr = new ItrConst(ifo); delete o; return; } if( itr->getname() == "!" ) { if( str_eq(c->getval(),"0") ) ifo.name = "1"; else ifo.name = "0"; itr = new ItrConst(ifo); delete o; return; } if( itr->getname() == "-" ) { string s = c->getval(); if( s.size() && s[0] == '-' ) s.erase(0,1); else s = "-" +s; ifo.name = s; itr = new ItrConst(ifo); delete o; return; } throw LT+" internal: const evaluation "+itr->getname(); } /** 8.5.5 General evaluator switch **/ void constEval(ITR** p) { ITR *& itr = *p; try{ if( dynamic_cast(itr) ) return constEval2(p); if( dynamic_cast(itr) ) return constEval2(p); if( dynamic_cast(itr) ) return constEval1(p); if( dynamic_cast(itr) ) return constEvalArray(p); if( dynamic_cast(itr) ) return constEval2(p); if( dynamic_cast(itr) ) return constEval2(p); if( dynamic_cast(itr) ) return constEval3(p); }catch(string e) { Warning(LT+itr->errinfo()+" "+e); return; } throw LT+itr->errinfo()+" internal: const evaluation '"+itr->typname()+"'"; } /** 8.5.6 Warning function **/ void Warning(const string& s) { static std::set ws; if( ws.find(s) != ws.end() ) return; ws.insert(s); std::cerr<<"Warning "<children_size() != 2 ) throw LT; /* Multiplicative [*] Variable [a] Variable [b] Postfix [(] Label [_mul] Expression-list Variable [a] Variable [b] */ ITR * c1 = itr->child(0); ITR * c2 = itr->child(1); ITR::itrinfo ifo = itr->getinfo(); ifo.name = "("; ItrPostExpr * post = new ItrPostExpr(ifo); ifo.name = fun; ItrLab * lab = new ItrLab(ifo); ifo.name = ""; ItrExprList * lst = new ItrExprList(ifo); c1->setParent(0); c2->setParent(0); itr->dropkids(); lst->addkids(c1,c2); post->addkids(lab,lst); delete itr; itr = post; } /** 8.5.8 General multiplicative switch **/ void multEval(ITR** p) { ITR *& itr = *p; if( !dynamic_cast(itr) ) return; if( itr->getname() == "*" ) return multEval(p,"_mul"); if( itr->getname() == "/" ) return multEval(p,"_div"); if( itr->getname() == "%" ) return multEval(p,"_mod"); throw LT; } /** 8.5.9 Boolean conversion **/ void addBoolKid(ITR* parent, ITR * bkid, ITR::itrinfo ifo) { if( isBool(bkid) ) { parent->addkid(bkid); return; } ifo.name = "!="; ItrEqualExpr * eq = new ItrEqualExpr(ifo); ifo.name = "0"; ItrConst * z = new ItrConst(ifo); eq->addkids(bkid,z); parent->addkid(eq); } void addIntKid(ITR* parent, ITR * ikid, ITR::itrinfo ifo) { if( !isBool(ikid) ) { parent->addkid(ikid); return; } ifo.name = ""; ItrCondExpr * cond = new ItrCondExpr(ifo); ifo.name = "0"; ItrConst * z = new ItrConst(ifo); ifo.name = "1"; ItrConst * n = new ItrConst(ifo); cond->addkid(ikid); cond->addkids(n,z); parent->addkid(cond); } /** 8.6 Parser **/ struct parseinfo{ ITR * itr; ITR::kid k; string msg; parseinfo(): itr(0) {} parseinfo(ITR *p, ITR::kid ak): itr(p), k(ak) {} parseinfo(const string &m): itr(0), msg(m) {} }; class dbg{ static vector stack; public: dbg(const ITR::kid& i, const string& s) { string r = s+"\t"+err(i)+name(i); stack.push_back(r); } ~dbg(){ stack.pop_back(); } static string dump(); }; // dbg vector dbg::stack; string dbg::dump() { return ""; //string r="\n"; //for( size_t i=0; igetname()!="EOF" ) break; children.pop_back(); } } /** 8.6.2 Declaration **/ parseinfo ItrDeclaration::parse(kid i, Context &curc) { dbg db(i,"2 decl-tion"); Context myc(curc); itrinfo ifo(i); bool ext = false; if( isKeyword(i,"extern") ) { ext=true; ifo.name = name(i++); } else ifo.name = ""; parseinfo tni = ItrTypeName::parse(i,myc); if ( !tni.itr ) return tni; ItrDeclaration * decl = new ItrDeclaration( ifo ); i = tni.k; decl->addkid(tni.itr); for(;;) { parseinfo idi; if( !ext ) idi = ItrDeclarator::parse(i,myc); else idi = ItrDeclarator::parse_extern(i,myc); if( !idi.itr ) { delete decl; return idi; } i = idi.k; decl->addkid(idi.itr); if( !isSymbol(i,"," ) ) break; ++i; } if( !isSymbol(i,";") ) return parseinfo(LT+err(i)+" expected ';', got '"+name(i)+"'"); curc.swap(myc); return parseinfo(decl,++i); } /** 8.6.3 TypeName **/ parseinfo ItrTypeName::parse(kid i, Context &) { dbg db(i,"3 typename"); if( !isKeyword(i,"void") && !isKeyword(i,"int") && !isKeyword(i,"char") ) { return parseinfo(LT+err(i) +" type name expected, got '"+name(i)+"'"); } ItrKeyword * nkw = new ItrKeyword((*i)->getinfo()); ++i; while( isSymbol(i,"*") ) ++i; return parseinfo( nkw, i ); } /** 8.6.4 Declarator **/ /** 8.6.4.1 Global **/ parseinfo ItrDeclarator::parse(kid i, Context &c) { dbg db(i,"4 decl-tor"); if( c.size() < 1 ) throw LT; if( c.size() > 1 ) return parse_stk(i,c); if( !isId(i) ) return parseinfo(LT+err(i)+" identifier expected"); itrinfo id(i); kid j=i; ++i; if( isSymbol(i,"=") ) { c.addVar((*j)->getname(),Context::VAR,0); itrinfo ifo(i); parseinfo ex = ItrAssExpr::parse(++i,c); if( !ex.itr ) return ex; ItrDeclarator * decl = new ItrDeclarator(ifo); decl->addkids(new ItrId(id), ex.itr); c.addVar(id.name,Context::VAR,decl); return parseinfo(decl,ex.k); } if( isSymbol(i,"[") ) { kid j2=i; itrinfo ifo(i); if( isSymbol(++i,"]") && isSymbol(++i,"=") ) { ItrString * s = dynamic_cast(*++i); if( !s ) return parseinfo(LT+err(i)+" expecting string"); ifo.name = "\""; ItrDeclarator * decl = new ItrDeclarator(ifo); decl->addkids(new ItrId(id), new ItrString(s->getinfo())); c.addVar(id.name,Context::LAB,decl); return parseinfo(decl,++i); } i=j2; } if( isSymbol(i,"[") ) { c.addVar((*j)->getname(),Context::LAB,0); itrinfo ifo(i); parseinfo ex = ItrAssExpr::parse(++i,c); if( !ex.itr ) return ex; if( !isSymbol(ex.k,"]") ) return parseinfo(LT+err(i)+" expected ']'"); if( !dynamic_cast(ex.itr) ) return parseinfo(LT+err(i)+" "+id.name +"[] size not evaluate to const"); ItrDeclarator * decl = new ItrDeclarator(ifo); decl->addkids(new ItrId(id), ex.itr); c.addVar(id.name,Context::LAB,decl); return parseinfo(decl,++ex.k); } itrinfo ifo = id; ifo.name = "0"; ItrDeclarator * decl = new ItrDeclarator(ifo); decl->addkid( new ItrId(id) ); c.addVar(id.name,Context::VAR,decl); return parseinfo(decl,i); } /** 8.6.4.2 Extern **/ parseinfo ItrDeclarator::parse_extern(kid i, Context &c) { dbg db(i,"4 decl-torx"); if( !isId(i) ) return parseinfo(LT+err(i)+" identifier expected"); itrinfo id(i); kid j=i; ++i; if( isSymbol(i,"[") ) { c.addVar((*j)->getname(),Context::LAB,0); itrinfo ifo(i); if( !isSymbol(++i,"]") ) return parseinfo(LT+err(i)+" expected ']'"); ItrDeclarator * decl = new ItrDeclarator(ifo); decl->addkid(new ItrId(id)); c.addVar(id.name,Context::LAB,0); return parseinfo(decl,++i); } ITR * iid = new ItrId(id); c.addVar(id.name,Context::VAR,0); return parseinfo(iid,i); } /** 8.6.4.3 Stack **/ parseinfo ItrDeclarator::parse_stk(kid i, Context &c) { dbg db(i,"4 decl-tor"); if( !isId(i) ) return parseinfo(LT+err(i)+" identifier expected"); itrinfo id(i); kid j=i; ++i; if( isSymbol(i,"=") ) { itrinfo ifo(i); parseinfo ex = ItrAssExpr::parse(++i,c); if( !ex.itr ) return ex; ItrDeclarator * decl = new ItrDeclarator(ifo); ItrStk * name = new ItrStk( id, c.get_bp() ); decl->addkid(name); addIntKid(decl,ex.itr,ifo); c.addVar(id.name,Context::STK,name); return parseinfo(decl,ex.k); } if( isSymbol(i,"[") ) { kid j2=i; itrinfo ifo(i); if( isSymbol(++i,"]") && isSymbol(++i,"=") ) { ItrString * s = dynamic_cast(*++i); if( !s ) return parseinfo(LT+err(i)+" expecting string"); ifo.name = "\""; ItrDeclarator * decl = new ItrDeclarator(ifo); ItrStk * name = new ItrStk( id, c.get_bp(s->size()+1) ); decl->addkid( name ); decl->addkid( new ItrString(s->getinfo()) ); c.addVar(id.name,Context::STK,name); return parseinfo(decl,++i); } i=j2; } if( isSymbol(i,"[") ) { itrinfo ifo(i); parseinfo ex = ItrAssExpr::parse(++i,c); if( !ex.itr ) return ex; if( !isSymbol(ex.k,"]") ) return parseinfo(LT+err(i)+" expected ']'"); ItrConst * val = dynamic_cast(ex.itr); if( !val ) return parseinfo(LT+err(i)+" "+id.name +"[] size not evaluate to const"); int ival = atoi( val->getval().c_str() ); ItrDeclarator * decl = new ItrDeclarator(ifo); ItrStk * name = new ItrStk(id,c.get_bp(ival)); decl->addkid(name); addIntKid(decl,ex.itr,ifo); c.addVar(id.name,Context::STK,name); return parseinfo(decl,++ex.k); } itrinfo ifo = id; ifo.name = "0"; ItrDeclarator * decl = new ItrDeclarator(ifo); ItrStk * name = new ItrStk( id, c.get_bp() ); decl->addkid( name ); c.addVar(id.name,Context::STK,name); return parseinfo(decl,i); } /** 8.6.5 Function decl **/ parseinfo ItrFunc::parse(kid i, Context &c) { dbg db(i,"5 funcion"); parseinfo tni = ItrTypeName::parse(i,c); if ( !tni.itr ) return parseinfo(""); // same as decl i = tni.k; if( !isId(i) ) return parseinfo(""); // same as decl itrinfo ifo(i); ++i; if ( !isSymbol(i,"(") ) // return silent to allow declaration message return parseinfo(""); ++i; parseinfo argl = ItrParamTypeList::parse(i,c); if( argl.itr ) i = argl.k; else throw LT; ItrParamTypeList * argl_itr = dynamic_cast(argl.itr); if( !argl_itr ) throw LT; if ( !isSymbol(i,")") ) return parseinfo(LT+err(i) + " expected ')'"); ++i; c.push_scope(); c.addVar(ifo.name,Context::LAB,0); argl_itr->addVars(c); c.reset_bp(); parseinfo block_info = ItrBlock::parse(i,c,false); c.pop_scope(); if( !block_info.itr ) { if ( !isSymbol(i,";") ) return block_info; ++i; if( !c.getVar(ifo.name,0) ) c.addVar(ifo.name,Context::LAB,0); } else { i = block_info.k; } ItrFunc * func = new ItrFunc( ifo, c.get_bp()-1 ); func->addkids(tni.itr,argl.itr); if( block_info.itr ) { func->addkid(block_info.itr); c.addVar(ifo.name,Context::LAB,func); } return parseinfo(func,i); } /** 8.6.6 ParamTypeList **/ parseinfo ItrParamTypeList::parse(kid i, Context &c) { dbg db(i,"6 paramlist"); itrinfo ifo(i); ifo.name = ""; ItrParamTypeList * pl = new ItrParamTypeList(ifo); int bpi = -1; for(;;) { parseinfo typ = ItrTypeName::parse(i,c); if( !typ.itr ) break; i = typ.k; ItrStk * id = new ItrStk(( isId(i)?info(i++):itrinfo() ),--bpi); pl->addkid(id); if( !isSymbol(i,",") ) break; ++i; } return parseinfo(pl,i); } /** 8.6.7 Block **/ parseinfo ItrBlock::parse(kid i, Context &c, bool newscope) { dbg db(i,"7 block"); if( !isSymbol(i,"{") ) return parseinfo(""); // something other itrinfo ifo(i); ifo.name=""; ItrBlock * block = new ItrBlock(ifo); ++i; parseinfo stmt; if( newscope ) c.push_scope(); for(;;) { stmt = ItrStatement::parse(i,c); if( !stmt.itr ) break; i = stmt.k; block->addkid(stmt.itr); } if( newscope ) c.pop_scope(); if( !isSymbol(i,"}") ) return stmt; return parseinfo(block,++i); } /** 8.6.8 Statement **/ parseinfo ItrStatement::parse(kid i, Context &c) { dbg db(i,"8 statement"); parseinfo rinfo; ItrSymbol * sym = dynamic_cast(*i); if( sym && sym->getname() == ";" ) { ItrStatement * stmt = new ItrStatement(sym->getinfo()); rinfo.k = ++i; rinfo.itr = stmt; return rinfo; } parseinfo block = ItrBlock::parse(i,c,true); if( block.itr ) return block; parseinfo keywst = ItrKeyStatement::parse(i,c); if( keywst.itr ) return keywst; parseinfo labstmt = ItrLabStatement::parse(i,c); if( labstmt.itr ) return labstmt; parseinfo decl = ItrDeclaration::parse(i,c); if( decl.itr ) return decl; parseinfo expr = ItrExpr::parse(i,c); if( !expr.itr ) { if( block.msg != "" ) return block; return expr; } i = expr.k; sym = dynamic_cast(*i); if( !sym || sym->getname() != ";" ) { rinfo.msg = LT+(*i)->errinfo() + " ';' expected, got: " + (*i)->getname(); return rinfo; } expr.k = ++i; return expr; } /** 8.6.9 Keyword statement **/ parseinfo ItrKeyStatement::parse(kid i, Context &c) { dbg db(i,"9 keystmt"); ItrKeyword * id = dynamic_cast(*i); if( !id ) return parseinfo(LT+" not keyword"); ++i; if( id->getname() == "for" ) return parse_for(i,c); if( id->getname() == "while" ) return parse_while(i,c); if( id->getname() == "if" ) return parse_if(i,c); if( id->getname() == "goto" ) return parse_goto(i,c); if( id->getname() == "continue" ) return parse_continue(i,c); if( id->getname() == "break" ) return parse_break(i,c); if( id->getname() == "return" ) { parseinfo expr = ItrExpr::parse(i,c); if( expr.itr ) i = expr.k; if( !isSymbol(i,";") ) { if( expr.itr ) return parseinfo(LT+err(i)+" expected ';', got '"+name(i)+"'"); else return expr; } ItrKeyStatement * ks = new ItrKeyStatement(id->getinfo()); if( expr.itr ) addIntKid(ks,expr.itr,id->getinfo()); return parseinfo(ks,++i); } return parseinfo(LT+" not keyword"); } /** 8.6.9.1 Loop for **/ parseinfo ItrKeyStatement::parse_for(kid i, Context &c) { Context myc(c); myc.push_scope(); itrinfo ifo(i); ifo.name = "for"; if( !isSymbol(i,"(") ) throw LT+err(i)+" for-loop expecting '('"; parseinfo st1 = ItrStatement::parse(++i,myc); if( !st1.itr ) throw st1.msg; parseinfo ex1 = ItrExpr::parse(st1.k,myc); if( !ex1.itr ) { i = st1.k; ex1.itr = new ItrConst(itrinfo("",0,"1")); } else i = ex1.k; if( !isSymbol(i,";") ) throw LT+err(i)+" for-loop expecting ';'"; parseinfo ex2 = ItrExpr::parse(++i,myc); if( !ex2.itr ) { ex2.itr = new ItrConst(itrinfo("",0,"0")); } else i = ex2.k; if( !isSymbol(i,")") ) throw LT+err(i)+" for-loop expecting ')'"; parseinfo st2 = ItrStatement::parse(++i,myc); if( !st2.itr ) throw st2.msg; ItrKeyStatement * fs = new ItrKeyStatement(ifo); fs->addkid(st1.itr); addBoolKid(fs,ex1.itr,ifo); fs->addkids(ex2.itr,st2.itr); // all good myc.pop_scope(); c.swap(myc); return parseinfo(fs,st2.k); } /** 8.6.9.2 Loop while **/ parseinfo ItrKeyStatement::parse_while(kid i, Context &c) { itrinfo ifo(i); ifo.name = "while"; if( !isSymbol(i,"(") ) throw LT+err(i)+" while-loop expecting '('"; parseinfo ex = ItrExpr::parse(++i,c); if( !ex.itr ) throw ex.msg; i = ex.k; if( !isSymbol(i,")") ) throw LT+err(i)+" while-loop expecting ')'"; parseinfo st = ItrStatement::parse(++i,c); if( !st.itr ) throw st.msg; ItrKeyStatement * ws = new ItrKeyStatement(ifo); addBoolKid(ws,ex.itr,ifo); ws->addkid(st.itr); return parseinfo(ws,st.k); } /** 8.6.9.3 Clause if **/ parseinfo ItrKeyStatement::parse_if(kid i, Context &c) { itrinfo ifo(i); ifo.name = "if"; if( !isSymbol(i,"(") ) throw LT+err(i)+" if-clause expecting '('"; parseinfo ex = ItrExpr::parse(++i,c); if( !ex.itr ) throw ex.msg; i = ex.k; if( !isSymbol(i,")") ) throw LT+err(i)+" if-clause expecting ')', got '"+(*i)->getname()+"'"; parseinfo st1 = ItrStatement::parse(++i,c); if( !st1.itr ) throw st1.msg; i = st1.k; parseinfo st2; if( isKeyword(i,"else") ) { st2 = ItrStatement::parse(++i,c); if( !st2.itr ) throw st2.msg; i = st2.k; } ItrKeyStatement * ifs = new ItrKeyStatement(ifo); addBoolKid(ifs,ex.itr,ifo); ifs->addkid(st1.itr); if( st2.itr ) ifs->addkid(st2.itr); return parseinfo(ifs,i); } /** 8.6.9.4 Goto **/ parseinfo ItrKeyStatement::parse_goto(kid i, Context &c) { itrinfo ifo(i); ifo.name = "goto"; parseinfo ex; kid j=i; if( isId(j) && isSymbol(++j,";") ) { string id = (*i)->getname(); ITR* ref=0; Context::vartype var_type = Context::VAR; if( c.getVar(id,&var_type,&ref) ) if( var_type!=Context::LAB ) goto expr; else c.addVar(id,Context::LAB,0); itrinfo ifo(i); ifo.ref = ref; ex.itr = new ItrLab(ifo); if( !ref ) c.addUnres(ex.itr); i = ++j; } else { expr: ex = ItrExpr::parse(i,c); if( !ex.itr ) throw ex.msg; i = ex.k; } ItrKeyStatement * gs = new ItrKeyStatement(ifo); gs->addkid(ex.itr); return parseinfo(gs,i); } /** 8.6.9.5 Continue **/ parseinfo ItrKeyStatement::parse_continue(kid i, Context &) { itrinfo ifo(i); ifo.name = "continue"; if( !isSymbol(i,";") ) throw LT+err(i)+" continue operator expecting ';'"; ItrKeyStatement * cs = new ItrKeyStatement(ifo); return parseinfo(cs,++i); } /** 8.6.9.6 Break **/ parseinfo ItrKeyStatement::parse_break(kid i, Context &) { itrinfo ifo(i); ifo.name = "break"; if( !isSymbol(i,";") ) throw LT+err(i)+" break operator expecting ';'"; ItrKeyStatement * bs = new ItrKeyStatement(ifo); return parseinfo(bs,++i); } /** 8.6.10 Labeled statement **/ parseinfo ItrLabStatement::parse(kid i, Context &c) { dbg db(i,"10 labst"); parseinfo rinfo; ItrId * id = dynamic_cast(*i); if( !id ) return parseinfo("Not identifier"); ++i; if( !isSymbol(i,":") ) return parseinfo(LT+(*i)->errinfo() + " ':' expected, got: "+ (*i)->getname()); ++i; parseinfo st = ItrStatement::parse(i,c); if( !st.itr ) return st; ItrLabStatement * kst = new ItrLabStatement(id->getinfo()); c.addVar(id->getname(),Context::LAB,kst); kst->addkid(st.itr); st.itr = kst; return st; } /** 8.6.11 Expression **/ parseinfo ItrExpr::parse(kid i, Context &c) { dbg db(i,"11 expr-ion"); parseinfo assexpr = ItrAssExpr::parse(i,c); if( !assexpr.itr ) return assexpr; return ItrExpr::parse(assexpr,c); } parseinfo ItrExpr::parse(parseinfo expr, Context &c) { kid i = expr.k; if( !isSymbol(i,",") ) return expr; itrinfo ifo = (*i)->getinfo(); ++i; parseinfo nextexpr = ItrAssExpr::parse(i,c); if( !nextexpr.itr ) return expr; ItrExpr * pex = new ItrExpr(ifo); pex->addkids(expr.itr, nextexpr.itr); nextexpr.itr = pex; return ItrExpr::parse(nextexpr,c); } /** 8.6.12 Assignment expression **/ parseinfo ItrAssExpr::parse(kid i, Context &c) { dbg db(i,"12 assexpr"); // this non trivial handling is due to // ItrUnarExpr being sub-sub of ItrCondExpr parseinfo unexpr = ItrUnarExpr::parse(i,c); if( !unexpr.itr ) return ItrCondExpr::parse(i,c); parseinfo assop_i = ItrAssOperator::parse_intl(unexpr.k); if( !assop_i.itr ) { unexpr.itr->unbind(c); delete unexpr.itr; return ItrCondExpr::parse(i,c); } parseinfo asse = ItrAssExpr::parse(assop_i.k,c); if( !asse.itr ) return asse; ItrAssExpr * ae = new ItrAssExpr(assop_i.itr->getinfo()); ae->addkid(unexpr.itr); addIntKid(ae,asse.itr,assop_i.itr->getinfo()); asse.itr = ae; return asse; } /** 8.6.13 Assignment operator **/ parseinfo ItrAssOperator::parse_intl(kid i) { dbg db(i,"13 assoper"); ItrSymbol * sm = dynamic_cast(*i); if( !sm ) return parseinfo(LT+" not symbol"); string s = sm->getname(); if( s=="=" || s=="-=" || s=="+=" || s=="*=" || s=="/=" || s=="%=" ) return parseinfo(sm,++i); return parseinfo(LT+" not assignment operator"); } /** 8.6.14 Equal expression **/ parseinfo ItrEqualExpr::parse(kid i, Context &c) { dbg db(i,"14 eqalex"); parseinfo rel = ItrRelExpr::parse(i,c); if( !rel.itr ) return rel; return parse(rel,c); } parseinfo ItrEqualExpr::parse(parseinfo rel, Context &c) { if( !isSymbol(rel.k,"==") && !isSymbol(rel.k,"!=") ) return rel; itrinfo ifo = (*rel.k)->getinfo(); parseinfo next = ItrRelExpr::parse(++rel.k,c); if( !next.itr ) return next; ItrEqualExpr * ee = new ItrEqualExpr(ifo); ee->addkid(rel.itr); ee->addkid(next.itr); next.itr = ee; return parse(next,c); } /** 8.6.15 Ralational expression **/ parseinfo ItrRelExpr::parse(kid i, Context &c) { dbg db(i,"15 relex"); parseinfo add = ItrAddExpr::parse(i,c); if( !add.itr ) return add; return parse(add,c); } parseinfo ItrRelExpr::parse(parseinfo add, Context &c) { if( !isSymbol(add.k,"<=") && !isSymbol(add.k,">=") && !isSymbol(add.k,">") && !isSymbol(add.k,"<") ) return add; itrinfo ifo = (*add.k)->getinfo(); parseinfo next = ItrAddExpr::parse(++add.k,c); if( !next.itr ) return next; ItrRelExpr * re = new ItrRelExpr(ifo); re->addkid(add.itr); re->addkid(next.itr); next.itr = re; return parse(next,c); } /** 8.6.16 Additive expression **/ parseinfo ItrAddExpr::parse(kid i, Context &c) { dbg db(i,"16 addex"); parseinfo mul = ItrMulExpr::parse(i,c); if( !mul.itr ) return mul; return parse(mul,c); } parseinfo ItrAddExpr::parse(parseinfo mul, Context &c) { if( !isSymbol(mul.k,"+") && !isSymbol(mul.k,"-") ) return mul; itrinfo ifo = (*mul.k)->getinfo(); parseinfo next = ItrMulExpr::parse(++mul.k,c); if( !next.itr ) return next; ItrAddExpr * ae = new ItrAddExpr(ifo); addIntKid(ae,mul.itr,ifo); addIntKid(ae,next.itr,ifo); next.itr = ae; constEval(&next.itr); return parse(next,c); } /** 8.6.17 Multiplicative expression **/ parseinfo ItrMulExpr::parse(kid i, Context &c) { dbg db(i,"17 mulex"); parseinfo cex = ItrUnarExpr::parse(i,c); if( !cex.itr ) return cex; return parse(cex,c); } void checkMulName(ITR * itr, Context &c); parseinfo ItrMulExpr::parse(parseinfo cex, Context &c) { if( !isSymbol(cex.k,"*") && !isSymbol(cex.k,"/") && !isSymbol(cex.k,"%") ) return cex; itrinfo ifo = (*cex.k)->getinfo(); parseinfo next = ItrUnarExpr::parse(++cex.k,c); if( !next.itr ) return next; ItrMulExpr * me = new ItrMulExpr(ifo); addIntKid(me,cex.itr,ifo); addIntKid(me,next.itr,ifo); next.itr = me; constEval(&next.itr); multEval(&next.itr); checkMulName(next.itr,c); return parse(next,c); } void checkMulName(ITR * itr, Context &c) { ItrPostExpr * post = dynamic_cast(itr); if( !post ) return; if( post->getname() != "(" ) throw LT; if( post->children_size() != 2 ) throw LT; ItrLab * lab = dynamic_cast(post->child(0)); if( !lab ) throw LT; string id = lab->getname(); ITR* ref=0; Context::vartype var_type = Context::VAR; if( !c.getVarTop(id,&var_type,&ref) ) { c.addUnres(lab); return; } if( var_type==Context::LAB ) { lab->setRef(ref); return; } throw LT+lab->errinfo()+" reserved identifier '"+id+"'"; } /** 8.6.18 Unary expression **/ parseinfo ItrUnarExpr::parse(kid i, Context &c) { dbg db(i,"18 unary"); parseinfo pfix = ItrPostExpr::parse(i,c); if( pfix.itr ) return pfix; if( isSymbol(i,"--") || isSymbol(i,"++") ) { itrinfo ifo = (*i)->getinfo(); parseinfo uei = ItrUnarExpr::parse(++i,c); if( !uei.itr ) return uei; ItrUnarExpr * ue = new ItrUnarExpr(ifo); ue->addkid(uei.itr); uei.itr = ue; return uei; } if( isSymbol(i,"&") || isSymbol(i,"*") || isSymbol(i,"+") || isSymbol(i,"-") || isSymbol(i,"!") ) { bool isbool = isSymbol(i,"!"); itrinfo ifo = (*i)->getinfo(); parseinfo cei = ItrUnarExpr::parse(++i,c); if( !cei.itr ) return cei; ItrUnarExpr * ue = new ItrUnarExpr(ifo); if( isbool ) addBoolKid(ue,cei.itr,ifo); else addIntKid(ue,cei.itr,ifo); cei.itr = ue; constEval(&cei.itr); return cei; } return pfix; } /** 8.6.19 Postfix expression **/ parseinfo ItrPostExpr::parse(kid i, Context &c) { dbg db(i,"19 postfix"); parseinfo prim = ItrPrimExpr::parse(i,c); if( !prim.itr ) return prim; return parse(prim,c); } parseinfo ItrPostExpr::parse(parseinfo pr, Context &c) { kid i = pr.k; if( isSymbol(i,"++") || isSymbol(i,"--") ) { ItrPostExpr * pe = new ItrPostExpr((*i)->getinfo()); pe->addkid(pr.itr); pr.k = ++i; pr.itr = pe; return parse(pr,c); } if( isSymbol(i,"[") ) { itrinfo ifo = (*i)->getinfo(); parseinfo expr = ItrExpr::parse(++i,c); if( !expr.itr ) return expr; if( !isSymbol(expr.k,"]") ) return parseinfo(LT+expr.itr->errinfo()+" expecting ']'"); ItrPostExpr * pe = new ItrPostExpr(ifo); pe->addkid(pr.itr); addIntKid(pe,expr.itr,ifo); expr.itr = pe; ++expr.k; constEval(&expr.itr); return parse(expr,c); } if( isSymbol(i,"(") ) { itrinfo ifo = (*i)->getinfo(); ++i; parseinfo list = ItrExprList::parse(i,c); if( list.itr ) i=list.k; if( !isSymbol(i,")") ) { if( list.itr ) return parseinfo(LT+err(i)+" expecting ')', got '"+name(i)+"'"); else return list; } ItrPostExpr * pe = new ItrPostExpr(ifo); pe->addkid(pr.itr); if( list.itr ) pe->addkid(list.itr); return parse(parseinfo(pe,++i),c); } return pr; } /** 8.6.20 Comma expression **/ parseinfo ItrExprList::parse(kid i, Context &c) { dbg db(i,"20 exlist"); itrinfo ifo(i); ifo.name = ""; ItrExprList * elist = new ItrExprList(ifo); parseinfo expr; for(;;) { expr = ItrAssExpr::parse(i,c); if( !expr.itr ) { elist->unbind(c); delete elist; return parseinfo(expr.msg); } i = expr.k; addIntKid(elist,expr.itr,ifo); if( !isSymbol(i,",") ) break; ++i; } if( elist->children_size() < 1 ) { elist->unbind(c); delete elist; return parseinfo(expr.msg); } return parseinfo(elist,i); } /** 8.6.21 Primary expression **/ parseinfo ItrPrimExpr::parse(kid i, Context &c) { dbg db(i,"21 primary"); parseinfo opio = ItrOpio::parse(i,c); if( opio.itr ) return opio; if( isConst(i) ) { ItrConst * ic = new ItrConst( (*i)->getinfo() ); return parseinfo( ic, ++i ); } if( isString(i) ) { ItrString *is = new ItrString( (*i)->getinfo() ); return parseinfo( is, ++i ); } if( isSymbol(i,"(") ) { itrinfo ifo(i++); parseinfo ex = ItrExpr::parse(i,c); if( !ex.itr ) return ex; if( !isSymbol(ex.k,")") ) { return parseinfo(LT+(*ex.k)->errinfo()+" expected ')'"); } ++ex.k; return ex; } if( isId(i) ) { string id = (*i)->getname(); ITR* ref=0; Context::vartype var_type = Context::VAR; if( !c.getVar(id,&var_type,&ref) ) throw LT+(*i)->errinfo()+" unknown identifier '"+id+"'"; itrinfo ifo(i); ifo.ref = ref; ITR * iid; if( var_type==Context::VAR ) iid = new ItrVar(ifo); else if( var_type==Context::LAB ) iid = new ItrLab(ifo); else if( var_type==Context::STK ) { if( !ref ) throw LT; // unresolved stack var? impossible ItrStk * decl = dynamic_cast(ref); if( !decl ) throw LT+ref->typname(); iid = decl->itrrepr(ifo); } else throw LT; // unknown type if( !ref ) c.addUnres(iid); // cannot be STK return parseinfo(iid,++i); } if( isChar(i) && name(i)=="EOF" ) return parseinfo(LT+(*i)->errinfo() +" unexpected End-of-File"); return parseinfo(LT+(*i)->errinfo() +" expected expression, got '"+name(i)+"'"+dbg::dump()); } /** 8.6.22 Input/Output operator **/ parseinfo ItrOpio::parse(kid i, Context &c) { dbg db(i,"22 oper-io"); if( !isKeyword(i,"__out" ) && !isKeyword(i,"__in" ) ) return parseinfo(LT+(*i)->errinfo() + " expected '__out/__in', got '"+(*i)->getname()+"'"); if( isKeyword(i,"__out" ) ) { itrinfo ifo = (*i)->getinfo(); ++i; parseinfo expr = ItrExpr::parse(i,c); if( !expr.itr ) return expr; ItrOpio * io = new ItrOpio(ifo); io->addkid(expr.itr); return parseinfo(io,expr.k); } if( isKeyword(i,"__in" ) ) { ItrOpio * io = new ItrOpio((*i)->getinfo()); return parseinfo(io,++i); } throw LT; } /** 8.6.23 Conditional expression **/ parseinfo ItrCondExpr::parse(kid i, Context &c) { dbg db(i,"23 cond-nal"); parseinfo lor = ItrLogOrExpr::parse(i,c); if( !lor.itr ) return lor; return parse(lor,c); } parseinfo ItrCondExpr::parse(parseinfo lor, Context &c) { if( !isSymbol(lor.k,"?") ) return lor; itrinfo ifo = (*lor.k)->getinfo(); parseinfo arg1 = ItrExpr::parse(++lor.k,c); if( !arg1.itr ) return arg1; if( !isSymbol(arg1.k,":") ) throw LT+(*lor.k)->errinfo()+" expected ':' in conditional expression (?:)"; parseinfo arg2 = ItrCondExpr::parse(++arg1.k,c); if( !arg2.itr ) return arg2; ItrCondExpr * ce = new ItrCondExpr(ifo); ce->addkid(lor.itr); ce->addkids(arg1.itr,arg2.itr); arg2.itr = ce; constEval(&arg2.itr); return parse(arg2,c); } /** 8.6.24 Logical Or expression **/ parseinfo ItrLogOrExpr::parse(kid i, Context &c) { dbg db(i,"24 log-or"); parseinfo land = ItrLogAndExpr::parse(i,c); if( !land.itr ) return land; return parse(land,c); } parseinfo ItrLogOrExpr::parse(parseinfo land, Context &c) { if( !isSymbol(land.k,"||") ) return land; itrinfo ifo = (*land.k)->getinfo(); parseinfo next = ItrLogAndExpr::parse(++land.k,c); if( !next.itr ) return next; ItrLogOrExpr * lre = new ItrLogOrExpr(ifo); addBoolKid( lre, land.itr, ifo ); addBoolKid( lre, next.itr, ifo ); next.itr = lre; constEval(&next.itr); return parse(next,c); } /** 8.6.25 Logical And expression **/ parseinfo ItrLogAndExpr::parse(kid i, Context &c) { dbg db(i,"25 log-and"); parseinfo eq = ItrEqualExpr::parse(i,c); if( !eq.itr ) return eq; return parse(eq,c); } parseinfo ItrLogAndExpr::parse(parseinfo eq, Context &c) { if( !isSymbol(eq.k,"&&") ) return eq; itrinfo ifo = (*eq.k)->getinfo(); parseinfo next = ItrEqualExpr::parse(++eq.k,c); if( !next.itr ) return next; ItrLogAndExpr * lae = new ItrLogAndExpr(ifo); addBoolKid( lae, eq.itr, ifo ); addBoolKid( lae, next.itr, ifo ); next.itr = lae; constEval(&next.itr); return parse(next,c); } /** 8.6.26 Stack replacement **/ ITR * ItrStk::itrrepr(itrinfo ifo) { /* int i,k[2],j; i-> *(bp+1) k-> bp+2 j-> *(bp+4) */ ifo.name = i2a(get_bpi()); ItrConst * c = new ItrConst(ifo); ifo.name = "@bp"; ItrVar * v = new ItrVar(ifo); ifo.name = "+"; ItrAddExpr * sum = new ItrAddExpr(ifo); sum->addkids(v,c); if( !parent ) throw LT; if( parent->getname() == "[" ) { return sum; } ifo.name = "*"; ItrUnarExpr * un = new ItrUnarExpr(ifo); un->addkid(sum); return un; } /** 8.6.27 Context implementation **/ /** 8.6.27.1 Dump **/ string Context::dump() { string r; r += "vars["; for( list::iterator j = vars.begin(); j!=vars.end(); ++j ) { scope & sc = *j; r += " {"; for( scope::iterator i=sc.begin(); i!=sc.end(); ++i ) { r += " " + i->first; if( i->second.typ == VAR ) r += ""; if( i->second.typ == LAB ) r += ":"; if( i->second.typ == STK ) r += "*"; if( !i->second.itr ) r += "(unref)"; } r += " } "; } r+=" "; if( !unres.empty() ) { r += "unres ["; for( list::iterator j = unres.begin(); j!=unres.end(); ++j ) r += " " + (*j)->getname(); r+=" ]\n"; } return r; } /** 8.6.27.2 Add variable **/ void Context::addVar(const string &s, vartype var, ITR * p) { if( vars.empty() ) throw LT; // check if var is defined in this scope scope::iterator i = vars.front().find(s); if( i==vars.front().end() || ( p && !i->second.itr ) ) { vars.front()[s] = ref(p,var); if( p && var != STK ) resolve(s,p); return; } ref &r = i->second; if( !p && !r.itr ) return; // ignore: both undefined if( !p && r.itr ) return; // ignore: was defined, now undef if( p && r.itr ) throw LT+p->errinfo()+" '"+s+"' was defined here "+r.itr->errinfo(); } /** 8.6.27.3 Get variable **/ bool Context::getVar(const string& s, vartype * var, ITR ** r) { if( vars.empty() ) throw LT; for( list::iterator j = vars.begin(); j!=vars.end(); ++j ) { scope & sc = *j; scope::iterator i = sc.find(s); if( i != sc.end() ) { if(r) *r = i->second.itr; if(var) *var = i->second.typ; return true; } } if(r) *r = 0; return false; } /** 8.6.27.4 Get global variable **/ bool Context::getVarTop(const string& s, vartype * var, ITR ** r) { if( vars.empty() ) throw LT; scope & sc = vars.back(); scope::iterator i = sc.find(s); if( i != sc.end() ) { if(r) *r = i->second.itr; if(var) *var = i->second.typ; return true; } if(r) *r = 0; return false; } /** 8.6.27.5 Resolve variable **/ void Context::resolve(const string& s, ITR *it) { list::iterator> fordel; for( list::iterator i=unres.begin(); i!=unres.end(); ++i ) { if( (*i)->getname() == s ) { (*i)->setRef(it); fordel.push_back(i); } } for( list::iterator>::iterator i=fordel.begin(); i!=fordel.end(); ++i ) { unres.erase(*i); } } /** 8.6.27.6 Add param list **/ void ItrParamTypeList::addVars(Context &c) { for( kid i = children.begin(); i!=children.end(); ++i ) { if( name(i) == "" ) continue; c.addVar( name(i), c.STK, *i ); } } } //hsqcomp