--- /dev/null
+/old/*
+/setup/*
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgallocregs.h"
+#include "cgdebug.h"
+#include "cgutil.h"
+
+#include <float.h>
+
+//quick debug
+//#define _DEBUG_ALLOCREGS
+
+//BIG debug!
+//#define _DEBUG_REGALLOC
+
+using namespace CG;
+using namespace std;
+
+static CGFlow *flow;
+static CGFrame *frame;
+
+struct Node;
+typedef set<Node*> NodeSet;
+typedef NodeSet::iterator NodeIter;
+
+static int reg_colors[4];
+
+static int n_passes,n_spills,max_spill_id;
+
+struct Node{
+ Node *succ,*pred,*_list;
+
+ CGReg *reg;
+ Node *alias;
+ int bank,color,degree;
+ float usage;
+ int block_count;
+ NodeSet edges,moves;
+
+ bool cant_spill;
+
+ Node():reg(0),alias(0),bank(-1),color(-1),degree(0),usage(0),block_count(1),cant_spill(false){
+ clear();
+ }
+
+ void setReg( CGReg *r ){
+ reg=r;
+ color=reg->color;
+ bank=frame->reg_banks[reg->type];
+ }
+
+ Node *unAlias(){
+ return alias ? alias->unAlias() : this;
+ }
+
+ void clear(){
+ _list=0;
+ succ=pred=this;
+ }
+
+ bool empty(){
+ return succ==this;
+ }
+
+ void insert( Node *t_list ){
+ if( _list==t_list ) return;
+ pred->succ=succ;
+ succ->pred=pred;
+ succ=t_list;
+ pred=succ->pred;
+ succ->pred=pred->succ=this;
+ _list=t_list;
+ }
+
+ int colors(){
+ return reg_colors[bank];
+ }
+
+ bool sigDegree(){
+ return degree>=colors();
+ }
+
+ bool colored(){
+ return color!=-1;
+ }
+
+ bool moveRelated(){
+ return moves.size()>0;
+ }
+};
+
+//node per enumerated tmp
+static vector<Node> nodes;
+
+//nodes not yet removed from graph
+static Node *_simplify,*_coalesce,*_freeze,*_spill;
+
+//nodes removed from graph
+static Node *_selected,*_coalesced,*_spilled,*_colored;
+
+static void freezeNode( Node *node );
+
+static void createNodes(){
+
+ nodes.clear();
+ nodes.resize( frame->regs.size() );
+
+ int k;
+ for( k=0;k<frame->regs.size();++k ){
+ CGReg *r=frame->regs[k];
+ nodes[k].setReg( r );
+ if( r->id!=k ) nodes[k].alias=&nodes[r->id];
+ }
+ for( k=0;k<nodes.size();++k ){
+ if( nodes[k].alias ){
+ CGReg *r=nodes[k].unAlias()->reg;
+ assert( frame->regs[r->id]->id==r->id );
+ }
+ }
+}
+
+static void createGraph(){
+
+ CGAsm *as;
+ CGBlockCIter blk_it;
+
+ //build interference edges
+ for( blk_it=flow->blocks.begin();blk_it!=flow->blocks.end();++blk_it ){
+ CGBlock *blk=*blk_it;
+
+ float use_cost=pow((double)10,(double)blk->loop_level);
+
+ //Increase usage for regs that are live_in and live_out
+ CGIntCIter int_it;
+ for( int_it=blk->live_in.begin();int_it!=blk->live_in.end();++int_it ){
+ if( blk->live_out.count(*int_it) ) nodes[*int_it].block_count+=1;
+ }
+
+ CGIntSet live=blk->live_out;
+
+ CGAsm *as=blk->end;
+
+ while( as!=blk->begin ){
+ as=as->pred;
+
+ Node *copy_src=0;
+ if( CGMov *t=as->stm->mov() ){
+ if( CGReg *lhs=t->lhs->reg() ){
+ if( CGReg *rhs=t->rhs->reg() ){
+ copy_src=&nodes[rhs->id];
+ }
+ }
+ }
+
+ CGIntCIter def_it;
+ for( def_it=as->def.begin();def_it!=as->def.end();++def_it ){
+ Node *x=&nodes[*def_it];
+ x->usage+=use_cost;
+
+ CGIntCIter live_it;
+ for( live_it=live.begin();live_it!=live.end();++live_it ){
+ Node *y=&nodes[*live_it];
+ if( (x!=y) && (y!=copy_src) && (x->bank==y->bank) ){
+ x->edges.insert( y );
+ y->edges.insert( x );
+ }
+ }
+ }
+
+ CGIntCIter use_it;
+ for( use_it=as->use.begin();use_it!=as->use.end();++use_it ){
+ Node *y=&nodes[*use_it];
+ y->usage+=use_cost;
+ }
+
+ live.erase( as->def );
+ live.insert( as->use );
+ }
+ }
+
+ //build 'move' edges
+ for( as=flow->assem.begin;as!=flow->assem.end;as=as->succ ){
+ if( CGMov *t=as->stm->mov() ){
+ if( CGReg *lhs=t->lhs->reg() ){
+ if( CGReg *rhs=t->rhs->reg() ){
+ Node *x=&nodes[lhs->id];
+ Node *y=&nodes[rhs->id];
+ if( x!=y && !x->edges.count(y) ){
+ x->moves.insert(y);
+ y->moves.insert(x);
+ }
+ }
+ }
+ }
+ }
+
+ //initial node degrees
+ int k;
+ for( k=0;k<nodes.size();++k ){
+ Node *node=&nodes[k];
+ node->degree=node->colored() ? 0x7fffffff : node->edges.size();
+ }
+
+#ifdef _DEBUG_REGALLOC
+ cout<<endl<<";--- Flow ---;"<<endl;
+ cout<<flow;
+ cout<<endl<<";--- Interference graph ---;"<<endl;
+ for( k=0;k<nodes.size();++k ){
+ Node *node=&nodes[k];
+ cout<<node->reg->id<<' ';
+ cout<<"(usage="<<node->usage;
+ cout<<" moves="<<node->moves.size();
+ cout<<" degree="<<node->degree;
+ if( node->degree ) cout<<" spill="<<(float)node->usage/(float)node->degree;
+ cout<<"):";
+ NodeIter it;
+ for( it=node->edges.begin();it!=node->edges.end();++it ){
+ cout<<' '<<(*it)->reg->id;
+ }
+ cout<<endl;
+ }
+#endif
+}
+
+static void createLists(){
+ //initialize lists
+ if( !_simplify ){
+ _simplify=new Node;
+ _coalesce=new Node;
+ _freeze=new Node;
+ _spill=new Node;
+
+ _selected=new Node;
+ _coalesced=new Node;
+ _spilled=new Node;
+ _colored=new Node;
+ }
+
+ _simplify->clear();
+ _coalesce->clear();
+ _freeze->clear();
+ _spill->clear();
+
+ _selected->clear();
+ _coalesced->clear();
+ _spilled->clear();
+ _colored->clear();
+
+ for( int k=0;k<nodes.size();++k ){
+ Node *node=&nodes[k];
+ if( node->alias ) node->insert( _coalesced );
+ else if( node->moveRelated() ) node->insert( _coalesce );
+ else freezeNode( node );
+ }
+}
+
+//decrement degree of a node.
+static void decDegree( Node *node ){
+ //dec degree
+ if( --node->degree!=node->colors()-1 ) return;
+
+ //OK node transitioned from sig to insig...
+
+ //move frozen neighbors to coalesce
+ NodeIter it;
+ for( it=node->edges.begin();it!=node->edges.end();++it ){
+ Node *t=(*it);
+ if( t->_list==_freeze ) t->insert( _coalesce );
+ }
+
+ //simplify if in spill
+ if( node->_list==_spill ) node->insert( _simplify );
+}
+
+//node has become non-move related
+//(node in coalesce or frozen)
+static void freezeNode( Node *node ){
+ assert( !node->moveRelated() );
+ if( node->colored() ) node->insert( _colored );
+ else if( node->sigDegree() ) node->insert( _spill );
+ else node->insert( _simplify );
+}
+
+//move node to select stack
+//decrement degree of neighboring nodes
+//(node is insig degree )
+static void selectNode( Node *node ){
+ assert( node->_list==_simplify || node->_list==_spill );
+ node->degree=0;
+ node->insert( _selected );
+ NodeIter it;
+ for( it=node->edges.begin();it!=node->edges.end();++it ){
+ Node *t=(*it);
+ decDegree( t );
+ }
+}
+
+//combine nodes a,b to node a
+//(a in coalesce, b in coalesce or frozen)
+static void combine( Node *a,Node *b ){
+ assert( a->_list==_coalesce && (b->_list==_coalesce||b->_list==_freeze) );
+
+ a->cant_spill=true;
+
+ b->alias=a;
+ b->insert( _coalesced );
+
+ NodeIter it;
+
+ //fix moves
+ for( it=b->moves.begin();it!=b->moves.end();++it ){
+ Node *t=*it;
+
+ t->moves.erase(b);
+ if( t==a ) continue;
+
+ if( !a->edges.count(t) ){
+ t->moves.insert(a);
+ a->moves.insert(t);
+ }else if( !t->moveRelated() ){
+ freezeNode(t);
+ }
+ }
+
+ //fix edges
+ for( it=b->edges.begin();it!=b->edges.end();++it ){
+ Node *t=(*it);
+
+ t->edges.erase(b);
+
+ if( a->edges.count(t) ){
+ decDegree(t);
+ continue;
+ }
+
+ t->edges.insert(a);
+ a->edges.insert(t);
+ if( t->_list==_selected ) continue;
+
+ if( !a->colored() ) ++a->degree;
+ if( !t->moves.count(a) ) continue;
+
+ t->moves.erase(a);
+ a->moves.erase(t);
+ if( !t->moveRelated() ) freezeNode(t);
+ }
+
+ a->usage+=b->usage;
+ if( !a->moveRelated() ) freezeNode( a );
+}
+
+//Briggs:
+//can we coalesce these 2 nodes?
+//(a in coalesce, b in coalesce or frozen)
+static bool canCoalesce( Node *a,Node *b ){
+ assert( a->_list==_coalesce && (b->_list==_coalesce||b->_list==_freeze||b->_list==_colored) );
+
+ if( b->colored() ) return false;
+
+ NodeIter it;
+
+ bool briggs;
+
+ //Briggs...
+ int n=0;
+ for( it=a->edges.begin();it!=a->edges.end();++it ){
+ Node *t=(*it);
+ if( t->sigDegree() ) ++n;
+ }
+ for( it=b->edges.begin();it!=b->edges.end();++it ){
+ Node *t=(*it);
+ if( t->sigDegree() && !t->edges.count(a) ) ++n;
+ }
+ briggs=n<a->colors();
+
+ return briggs;
+}
+
+static void simplify(){
+
+ Node *node=_simplify->succ;
+
+#ifdef _DEBUG_REGALLOC
+ cout<<"Simplifying:\t"<<node->reg->id<<endl;
+#endif
+
+ selectNode( node );
+}
+
+static void coalesce(){
+
+ Node *node=_coalesce->succ;
+
+ NodeIter it;
+ for( it=node->moves.begin();it!=node->moves.end();++it ){
+ Node *t=*it;
+
+ if( !canCoalesce(node,t) ) continue;
+
+#ifdef _DEBUG_REGALLOC
+ cout<<"Coalescing:\t"<<t->reg->id<<"->"<<node->reg->id<<endl;
+#endif
+ combine(node,t);
+
+ return;
+ }
+
+ if( node->colored() ) node->insert( _colored );
+ else node->insert( _freeze );
+}
+
+//freeze heuristic:
+//pick non-sig degree node with lowest move count
+//
+static void freeze(){
+
+ int min=0x7fffffff;
+ Node *node=0;
+ for( Node *t=_freeze->succ;t!=_freeze;t=t->succ ){
+ if( t->degree<min ){
+ node=t;
+ min=t->degree;
+ }
+ }
+
+#ifdef _DEBUG_REGALLOC
+ cout<<"Freezing:\t"<<node->reg->id<<endl;
+#endif
+
+ NodeIter it;
+ for( it=node->moves.begin();it!=node->moves.end();++it ){
+ Node *t=*it;
+ t->moves.erase(node);
+ if( !t->moveRelated() ) freezeNode( t );
+ }
+
+ node->moves.clear();
+ freezeNode( node );
+}
+
+static void spill(){
+
+ Node *node=0;
+ float min=FLT_MAX;
+ for( int pass=0;pass<2;++pass ){
+ for( Node *t=_spill->succ;t!=_spill;t=t->succ ){
+
+ if( t->cant_spill ) cout<<"Shouldn't spill:"<<t->reg->id<<endl;
+
+ //don't spill reg generated by prior spill
+ if( !pass && t->reg->id>=max_spill_id ) continue;
+
+ //No idea...!
+// if( !pass && t->reg->owner ) continue;
+
+// float cost=(float)t->usage/(float)t->degree;
+
+ //***** Munged cost *****//
+ float cost=(float)t->usage/((float)t->degree*(float)t->block_count);
+
+ if( cost<min ){
+ node=t;
+ min=cost;
+ }
+ }
+ if( node ) break;
+ cout<<"Pass "<<n_passes<<": trouble finding spill candidate\n"<<endl;
+ }
+
+ if( !node ) fail( "Unable to find spill candidate" );
+
+#ifdef _DEBUG_REGALLOC
+ cout<<"Spilling:\t"<<node->reg->id<<endl;
+#endif
+
+ selectNode( node );
+}
+
+static bool selectRegs(){
+
+#ifdef _DEBUG_REGALLOC
+ cout<<endl<<";--- Popping stack ---;"<<endl;
+#endif
+
+ while( !_selected->empty() ){
+
+ Node *node=_selected->pred;
+
+ //find color;
+ NodeIter it;
+
+ unsigned avail=frame->reg_masks[node->bank];
+
+ for( it=node->edges.begin();it!=node->edges.end();++it ){
+ Node *t=(*it);
+ if( t->color>=0 ) avail&=~(1<<t->color);
+ }
+
+ if( avail ){
+ int color=0;
+ for( ;!(avail&1);avail>>=1 ) ++color;
+ node->color=color;
+ node->insert( _colored );
+#ifdef _DEBUG_REGALLOC
+ cout<<"Colored:\t"<<node->reg->id<<"->"<<color<<endl;
+#endif
+ }else{
+ node->insert( _spilled );
+#ifdef _DEBUG_REGALLOC
+ cout<<"Spilled:\t"<<node->reg->id<<endl;
+#endif
+ }
+ }
+
+ if( _spilled->empty() ){
+ int k;
+ for( k=0;k<nodes.size();++k ){
+ Node *x=&nodes[k];
+ Node *y=x->unAlias();
+ assert( y->color>=0 );
+ x->reg->color=y->color;
+ }
+ return true;
+ }
+
+// max_spill_id=nodes.size();
+
+ for( Node *node=_spilled->succ;node!=_spilled;node=node->succ ){
+ frame->spillReg( node->reg,0 );
+ ++n_spills;
+ }
+
+ flow->liveness();
+ return false;
+}
+
+static int countBits( unsigned n ){
+ int c=0;
+ for( ;n;n>>=1 ) c+=(n&1);
+ return c;
+}
+
+static bool allocRegs(){
+
+ createNodes();
+ createGraph();
+ createLists();
+
+ if( !max_spill_id ) max_spill_id=nodes.size();
+
+ for(;;){
+ if( !_simplify->empty() ){
+ simplify();
+ }else if( !_coalesce->empty() ){
+ coalesce();
+ }else if( !_freeze->empty() ){
+ freeze();
+ }else if( !_spill->empty() ){
+ spill();
+ }else{
+ break;
+ }
+ }
+
+ return selectRegs();
+}
+
+void cgAllocRegs( CGFrame *t_frame ){
+
+ frame=t_frame;
+ flow=frame->flow;
+
+ for( int k=0;k<4;++k ){
+ reg_colors[k]=countBits( frame->reg_masks[k] );
+ }
+
+ nodes.clear();
+ max_spill_id=0;//0x7fffffff;
+
+ n_passes=0;
+ n_spills=0;
+
+ for(;;){
+ if( ++n_passes==100 ){
+ cout<<"INTERNAL ERROR! Register allocator terminally confused!"<<endl;
+ abort();
+ }
+ if( allocRegs() ) break;
+ }
+
+#ifdef _DEBUG_ALLOCREGS
+ if( n_spills ){
+ cout<<frame->fun->sym->value<<" passes="<<n_passes<<" spills="<<n_spills<<endl;
+ }
+#endif
+}
--- /dev/null
+
+#ifndef CGALLOCREGS_H
+#define CGALLOCREGS_H
+
+#include "cgframe.h"
+
+void cgAllocRegs( CGFrame *frame );
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+#include "cgasm.h"
+#include "cgutil.h"
+
+struct UseFinder : public CGVisitor{
+
+ CGAsm *as;
+
+ UseFinder( CGAsm *as ):as(as){}
+
+ CGExp *visit( CGExp *e ){
+ CGReg *r=e->reg();
+ while( r ){
+ as->use.insert(r->id);
+ r=r->owner;
+ }
+ return e;
+ }
+};
+
+CGAsm::CGAsm( CGStm *t,const char *s ):succ(0),pred(0),stm(t),assem(strdup(s)){
+ assert(stm);
+ assert(assem);
+ genUseDef();
+}
+
+void CGAsm::genUseDef(){
+
+ use.clear();
+ def.clear();
+ UseFinder uf(this);
+
+ if( CGXop *t=stm->xop() ){
+ if( CGReg *r=t->def ){
+ def.insert( r->id );
+ }
+ if( t->exp ) t->exp->visit( uf );
+ return;
+ }
+
+ if( CGMov *t=stm->mov() ){
+ if( CGReg *r=t->lhs->reg() ){
+ def.insert( r->id );
+ t->rhs->visit( uf );
+ return;
+ }
+ }
+
+ stm->visit( uf );
+}
+
+CGAsmSeq::CGAsmSeq():begin(0),end(0){
+ clear();
+}
+
+void CGAsmSeq::clear(){
+ begin=end=new CGAsm(CG::nop(),"");
+}
+
+CGAsm *CGAsmSeq::erase( CGAsm *as ){
+ CGAsm *succ=as->succ;
+ if( as->pred ) as->pred->succ=succ;
+ else begin=succ;
+ succ->pred=as->pred;
+ return succ;
+}
+
+CGAsm *CGAsmSeq::insert( CGAsm *as,CGAsm *succ ){
+ as->succ=succ;
+ if( as->pred=succ->pred ) as->pred->succ=as;
+ else begin=as;
+ succ->pred=as;
+ return as;
+}
--- /dev/null
+
+#ifndef CGASM_H
+#define CGASM_H
+
+#include "cgcode.h"
+#include "cgintset.h"
+
+struct CGAsm{
+ CGAsm *succ,*pred;
+
+ CGStm *stm;
+ char *assem;
+ CGIntSet use,def;
+
+ CGAsm( CGStm *t,const char *s );
+
+ void genUseDef();
+};
+
+struct CGAsmSeq{
+ CGAsm *begin,*end;
+
+ CGAsmSeq();
+
+ void clear();
+
+ CGAsm* erase( CGAsm *as );
+ CGAsm* insert( CGAsm *as,CGAsm *succ );
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgblock.h"
+
+void CGBlock::removeSucc( CGBlock *blk ){
+ CGBlockIter it;
+ for( it=succ.begin();it!=succ.end();++it ){
+ if( *it==blk ){
+ succ.erase(it);
+ return;
+ }
+ }
+}
+
+void CGBlock::removePred( CGBlock *blk ){
+ CGBlockIter it;
+ for( it=pred.begin();it!=pred.end();++it ){
+ if( *it==blk ){
+ pred.erase(it);
+ return;
+ }
+ }
+}
--- /dev/null
+
+#ifndef CGBLOCK_H
+#define CGBLOCK_H
+
+#include "cgasm.h"
+
+struct CGBlock;
+
+typedef std::vector<CGBlock*> CGBlockSeq;
+typedef CGBlockSeq::iterator CGBlockIter;
+typedef CGBlockSeq::const_iterator CGBlockCIter;
+
+struct CGBlock{
+ CGAsm *begin,*end;
+ CGBlockSeq succ,pred;
+ CGIntSet use,def,live_in,live_out;
+ std::set<CGBlock*> dom,loops;
+ int loop_level;
+
+ CGBlock():begin(0),end(0),loop_level(0){}
+
+ void removeSucc( CGBlock *blk );
+ void removePred( CGBlock *blk );
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgcode.h"
+#include "cgutil.h"
+
+CGStm *CGVisitor::visit( CGStm *t ){
+ return t;
+}
+
+CGExp *CGVisitor::visit( CGExp *e ){
+ return e;
+}
+
+CGNop *CGStm::nop(){ return 0; }
+CGXop *CGStm::xop(){ return 0; }
+CGRem *CGStm::rem(){ return 0; }
+CGAti *CGStm::ati(){ return 0; }
+CGAtd *CGStm::atd(){ return 0; }
+CGMov *CGStm::mov(){ return 0; }
+CGLab *CGStm::lab(){ return 0; }
+CGBra *CGStm::bra(){ return 0; }
+CGBcc *CGStm::bcc(){ return 0; }
+CGEva *CGStm::eva(){ return 0; }
+CGRet *CGStm::ret(){ return 0; }
+CGSeq *CGStm::seq(){ return 0; }
+
+CGMem *CGExp::mem(){ return 0; }
+CGLea *CGExp::lea(){ return 0; }
+CGCvt *CGExp::cvt(){ return 0; }
+CGUop *CGExp::uop(){ return 0; }
+CGBop *CGExp::bop(){ return 0; }
+CGJsr *CGExp::jsr(){ return 0; }
+CGVfn *CGExp::vfn(){ return 0; }
+CGScc *CGExp::scc(){ return 0; }
+CGEsq *CGExp::esq(){ return 0; }
+CGFrm *CGExp::frm(){ return 0; }
+CGTmp *CGExp::tmp(){ return 0; }
+CGLit *CGExp::lit(){ return 0; }
+CGSym *CGExp::sym(){ return 0; }
+CGDat *CGExp::dat(){ return 0; }
+CGReg *CGExp::reg(){ return 0; }
+
+CGStm::~CGStm(){
+}
+
+CGStm *CGStm::visit( CGVisitor &vis ){
+ assert(0);
+ return 0;
+}
+
+CGExp *CGExp::nonEsq(){
+ return this;
+}
+
+CGExp *CGExp::visit( CGVisitor &vis ){
+ assert(0);
+ return 0;
+}
+
+CGExp::~CGExp(){
+}
+
+bool CGExp::sideEffects(){
+ return false;
+}
+
+bool CGExp::equals( CGExp *exp ){
+ return false;
+}
+
+//***** CGNop *****
+CGNop *CGNop::nop(){
+ return this;
+}
+
+CGStm *CGNop::visit( CGVisitor &vis ){
+ return vis.visit( this );
+}
+
+//***** CGXop *****
+CGXop *CGXop::xop(){
+ return this;
+}
+
+CGStm *CGXop::visit( CGVisitor &vis ){
+ CGReg *r=def ? vis.visit(def)->reg() : 0;
+ CGExp *e=exp ? exp->visit(vis) : 0;
+ return vis.visit( r==def && e==exp ? this : CG::xop(op,r,e) );
+}
+
+//***** CGRem *****
+CGRem *CGRem::rem(){
+ return this;
+}
+
+CGStm *CGRem::visit( CGVisitor &vis ){
+ return vis.visit( this );
+}
+
+//***** CGAti *****
+CGAti *CGAti::ati(){
+ return this;
+}
+
+CGStm *CGAti::visit( CGVisitor &vis ){
+ CGMem *e=mem->visit(vis)->mem();
+ return vis.visit( e==mem ? this : CG::ati(e) );
+}
+
+//***** CGAtd *****
+CGAtd *CGAtd::atd(){
+ return this;
+}
+
+CGStm *CGAtd::visit( CGVisitor &vis ){
+ CGMem *a=mem->visit(vis)->mem();
+ CGSym *b=sym->visit(vis)->sym();
+ return vis.visit( a==mem && b==sym ? this : CG::atd(a,b) );
+}
+
+//***** CGMov *****
+CGMov *CGMov::mov(){
+ return this;
+}
+
+CGStm *CGMov::visit( CGVisitor &vis ){
+ CGExp *b=rhs->visit(vis);
+ CGExp *a=lhs->visit(vis);
+ return vis.visit( a==lhs && b==rhs ? this : CG::mov(a,b) );
+}
+
+//***** CGLab *****
+CGLab *CGLab::lab(){
+ return this;
+}
+
+CGStm *CGLab::visit( CGVisitor &vis ){
+ CGSym *e=vis.visit(sym)->sym();
+ return vis.visit( e==sym ? this : CG::lab(e) );
+}
+
+//***** CGBra *****
+CGBra *CGBra::bra(){
+ return this;
+}
+
+CGStm *CGBra::visit( CGVisitor &vis ){
+ CGSym *e=vis.visit(sym)->sym();
+ return vis.visit( e==sym ? this : CG::bra(e) );
+}
+
+//***** CGBcc *****
+CGBcc *CGBcc::bcc(){
+ return this;
+}
+
+CGStm *CGBcc::visit( CGVisitor &vis ){
+ CGExp *a=lhs->visit(vis);
+ CGExp *b=rhs->visit(vis);
+ CGSym *c=vis.visit(sym)->sym();
+ return vis.visit( a==lhs && b==rhs && c==sym ? this : CG::bcc(cc,a,b,c) );
+}
+
+//***** CGEva *****
+CGEva *CGEva::eva(){
+ return this;
+}
+
+CGStm *CGEva::visit( CGVisitor &vis ){
+ CGExp *e=exp->visit(vis);
+ return vis.visit( e==exp ? this : CG::eva(e) );
+}
+
+//***** CGRet *****
+CGRet *CGRet::ret(){
+ return this;
+}
+
+CGStm *CGRet::visit( CGVisitor &vis ){
+ CGExp *e=exp ? exp->visit(vis) : 0;
+ return vis.visit( e==exp ? this : CG::ret(e) );
+}
+
+//***** CGSeq *****
+CGSeq *CGSeq::seq(){
+ return this;
+}
+
+CGStm *CGSeq::visit( CGVisitor &vis ){
+ bool dup=false;
+ vector<CGStm*> t_stms;
+ int i;
+ for( i=0;i<stms.size();++i ){
+ CGStm *t=stms[i]->visit(vis);
+ if( t!=stms[i] ) dup=true;
+ t_stms.push_back( t );
+ }
+ return vis.visit( dup ? CG::seq( t_stms ) : this );
+}
+
+void CGSeq::push_back( CGStm *stm ){
+ stms.push_back( stm );
+}
+
+void CGSeq::push_front( CGStm *stm ){
+ stms.insert( stms.begin(),stm );
+}
+
+//***** CGMem *****
+CGMem *CGMem::mem(){
+ return this;
+}
+
+bool CGMem::sideEffects(){
+ return exp->sideEffects();
+}
+
+bool CGMem::equals( CGExp *e ){
+ CGMem *t=e->mem();
+ if( !t || type!=t->type || offset!=t->offset || flags!=t->flags ) return false;
+ return exp->equals(t->exp);
+}
+
+CGExp *CGMem::visit( CGVisitor &vis ){
+ CGExp *e=exp->visit(vis);
+ return vis.visit( e==exp ? this : CG::mem(type,e,offset) );
+}
+
+//***** CGLea *****
+CGLea *CGLea::lea(){
+ return this;
+}
+
+bool CGLea::sideEffects(){
+ return exp->sideEffects();
+}
+
+bool CGLea::equals( CGExp *e ){
+ CGLea *t=e->lea();
+ if( !t || type!=t->type ) return false;
+ return exp->equals(t->exp);
+}
+
+CGExp *CGLea::visit( CGVisitor &vis ){
+ CGExp *e=exp->visit(vis);
+ return vis.visit( e==exp ? this : CG::lea(e) );
+}
+
+//***** CGCvt *****
+CGCvt *CGCvt::cvt(){
+ return this;
+}
+
+bool CGCvt::sideEffects(){
+ return exp->sideEffects();
+}
+
+bool CGCvt::equals( CGExp *e ){
+ CGCvt *t=e->cvt();
+ if( !t || type!=t->type ) return false;
+ return exp->equals(t->exp);
+}
+
+CGExp *CGCvt::visit( CGVisitor &vis ){
+ CGExp *e=exp->visit(vis);
+ return vis.visit( e==exp ? this : CG::cvt(type,e) );
+}
+
+//***** CGUop *****
+CGUop *CGUop::uop(){
+ return this;
+}
+
+bool CGUop::sideEffects(){
+ return exp->sideEffects();
+}
+
+bool CGUop::equals( CGExp *e ){
+ CGUop *t=e->uop();
+ return t && type==t->type && exp->equals(t->exp);
+}
+
+CGExp *CGUop::visit( CGVisitor &vis ){
+ CGExp *e=exp->visit(vis);
+ return vis.visit( e==exp ? this : CG::uop(op,e) );
+}
+
+//***** CGBop *****
+CGBop *CGBop::bop(){
+ return this;
+}
+
+bool CGBop::commutes(){
+ switch(op){
+ case CG_ADD:case CG_MUL:case CG_AND:case CG_ORL:case CG_XOR:
+ return true;
+ }
+ return false;
+}
+
+bool CGBop::sideEffects(){
+ return lhs->sideEffects() || rhs->sideEffects();
+}
+
+bool CGBop::equals( CGExp *e ){
+ CGBop *t=e->bop();
+ if( !t || type!=t->type || op!=t->op ) return false;
+ if( lhs->equals(t->lhs) && rhs->equals(t->rhs) ) return true;
+ switch(op){
+ case CG_ADD:case CG_MUL:break;
+ default:return false;
+ }
+ return lhs->equals(t->rhs) && rhs->equals(t->lhs);
+}
+
+CGExp *CGBop::visit( CGVisitor &vis ){
+ CGExp *a=lhs->visit(vis);
+ CGExp *b=rhs->visit(vis);
+ return vis.visit( a==lhs && b==rhs ? this : CG::bop(op,a,b) );
+}
+
+//***** CGJsr *****
+CGJsr *CGJsr::jsr(){
+ return this;
+}
+
+bool CGJsr::sideEffects(){
+ return true;
+}
+
+bool CGJsr::equals( CGExp *e ){
+ CGJsr *t=e->jsr();
+ if( !t || type!=t->type || args.size()!=t->args.size() ) return false;
+ if( exp->equals(t->exp) ) return false;
+ for( int k=0;k<args.size();++k ){
+ if( !args[k]->equals(t->args[k]) ) return false;
+ }
+ return true;
+}
+
+CGExp *CGJsr::visit( CGVisitor &vis ){
+ CGExp *t_exp=exp->visit(vis);
+ bool copy=t_exp!=exp;
+ vector<CGExp*> t_args;
+ t_args.resize(args.size());
+ for( int k=0;k<args.size();++k ){
+ t_args[k]=args[k]->visit(vis);
+ if( t_args[k]!=args[k] ) copy=true;
+ }
+ if( !copy ) return vis.visit( this );
+ CGJsr *t=CG::jsr(type,call_conv,t_exp,t_args );
+ return vis.visit( t );
+}
+
+//***** CGVfn *****
+CGVfn *CGVfn::vfn(){
+ return this;
+}
+
+bool CGVfn::sideEffects(){
+ return exp->sideEffects() || self->sideEffects();
+}
+
+bool CGVfn::equals( CGExp *e ){
+ CGVfn *t=e->vfn();
+ if( !t || type!=t->type ) return false;
+ return exp->equals(t->exp) && self->equals(t->self);
+}
+
+CGExp *CGVfn::visit( CGVisitor &vis ){
+ CGExp *a=exp->visit(vis);
+ CGExp *b=self->visit(vis);
+ return vis.visit( a==exp && b==self ? this : CG::vfn(a,b) );
+}
+
+//***** CGScc *****
+CGScc *CGScc::scc(){
+ return this;
+}
+
+bool CGScc::sideEffects(){
+ return lhs->sideEffects() || rhs->sideEffects();
+}
+
+bool CGScc::equals( CGExp *e ){
+ CGScc *t=e->scc();
+ if( !t || type!=t->type || cc!=t->cc ) return false;
+ return lhs->equals(t->lhs) && rhs->equals(t->rhs);
+}
+
+CGExp *CGScc::visit( CGVisitor &vis ){
+ CGExp *a=lhs->visit(vis);
+ CGExp *b=rhs->visit(vis);
+ return vis.visit( a==lhs && b==rhs ? this : CG::scc(cc,a,b) );
+}
+
+//***** CGEsq *****
+CGEsq *CGEsq::esq(){
+ return this;
+}
+
+CGExp *CGEsq::nonEsq(){
+ return rhs->nonEsq();
+}
+
+bool CGEsq::sideEffects(){
+ return true;
+}
+
+bool CGEsq::equals( CGExp *e ){
+ CGEsq *t=e->esq();
+ if( !t || type!=t->type ) return false;
+ return rhs->equals(t->rhs);
+}
+
+CGExp *CGEsq::visit( CGVisitor &vis ){
+ CGStm *a=lhs->visit(vis);
+ CGExp *b=rhs->visit(vis);
+ return vis.visit( a==lhs && b==rhs ? this : CG::esq(a,b) );
+}
+
+//***** CGFrm *****
+CGFrm *CGFrm::frm(){
+ return this;
+}
+
+bool CGFrm::equals( CGExp *e ){
+ return e->frm() ? true : false;
+}
+
+CGExp *CGFrm::visit( CGVisitor &vis ){
+ return vis.visit(this);
+}
+
+//***** CGTmp *****
+CGTmp *CGTmp::tmp(){
+ return this;
+}
+
+bool CGTmp::equals( CGExp *e ){
+ CGTmp *t=e->tmp();
+ if( !t || type!=t->type ) return false;
+ return ident==t->ident;
+}
+
+CGExp *CGTmp::visit( CGVisitor &vis ){
+ return vis.visit(this);
+}
+
+//***** CGReg *****
+CGReg *CGReg::reg(){
+ return this;
+}
+
+bool CGReg::equals( CGExp *e ){
+ CGReg *t=e->reg();
+ return t ? id==t->id : false;
+}
+
+CGExp *CGReg::visit( CGVisitor &vis ){
+ return vis.visit(this);
+}
+
+//***** CGLit *****
+CGLit *CGLit::lit(){
+ return this;
+}
+
+bool CGLit::equals( CGExp *e ){
+ CGLit *t=e->lit();
+ if( !t || type!=t->type ) return false;
+ if( isfloat() ) return float_value==t->float_value;
+ return int_value==t->int_value;
+}
+
+CGExp *CGLit::visit( CGVisitor &vis ){
+ return vis.visit(this);
+}
+
+//***** CGSym *****
+CGSym *CGSym::sym(){
+ return this;
+}
+
+bool CGSym::equals( CGExp *e ){
+ CGSym *t=e->sym();
+ return t && value==t->value && linkage==t->linkage;
+}
+
+CGExp *CGSym::visit( CGVisitor &vis ){
+ return vis.visit(this);
+}
+
+//***** CGDat *****
+CGDat *CGDat::dat(){
+ return this;
+}
+
+bool CGDat::equals( CGExp *e ){
+ CGDat *t=e->dat();
+ if( !t || value!=t->value || linkage!=t->linkage || exps.size()!=t->exps.size() ) return false;
+ for( int k=0;k<t->exps.size();++k ){
+ if( !exps[k]->equals(t->exps[k]) ) return false;
+ }
+ return true;
+}
+
+CGExp *CGDat::visit( CGVisitor &vis ){
+ bool copy=false;
+ vector<CGExp*> t_exps;
+ t_exps.resize( exps.size() );
+ for( int k=0;k<exps.size();++k ){
+ t_exps[k]=exps[k]->visit(vis);
+ if( t_exps[k]!=exps[k] ) copy=true;
+ }
+ if( !copy ) return vis.visit(this);
+ CGDat *t=new CGDat;
+ t->type=type;t->value=value;t->linkage=linkage;t->exps=t_exps;
+ return vis.visit( t );
+}
+
+void CGDat::push_back( CGExp *exp ){
+ exps.push_back(exp);
+}
--- /dev/null
+
+#ifndef CGCODE_H
+#define CGCODE_H
+
+//calling conventions
+enum{
+ CG_CDECL=1,
+ CG_STDCALL=2
+};
+
+//data types
+enum{
+ CG_VOID=-1,
+ CG_PTR,
+ CG_INT8,CG_INT16,
+ CG_INT32,CG_INT64,
+ CG_FLOAT32,CG_FLOAT64,
+ CG_CSTRING,CG_BSTRING,CG_BINFILE,CG_LABEL
+};
+
+//condition codes
+enum{
+ CG_EQ,CG_NE,
+ CG_LT,CG_GT,CG_LE,CG_GE,
+ CG_LTU,CG_GTU,CG_LEU,CG_GEU
+};
+
+//unary operators for cguop
+enum{
+ CG_NEG,CG_NOT,CG_ABS,CG_SGN
+};
+
+//binary operators for cgbop
+enum{
+ CG_ADD,CG_SUB,CG_MUL,CG_DIV,CG_MOD,
+ CG_AND,CG_ORL,CG_XOR,CG_SHL,CG_SHR,CG_SAR,
+ CG_MIN,CG_MAX
+};
+
+//linkage flags
+enum{
+ CG_INTERNAL,CG_IMPORT,CG_EXPORT
+};
+
+//statements
+struct CGStm;
+struct CGNop;
+struct CGXop;
+struct CGRem;
+struct CGAti;
+struct CGAtd;
+struct CGMov;
+struct CGLab;
+struct CGBra;
+struct CGBcc;
+struct CGEva;
+struct CGRet;
+struct CGSeq;
+
+//expressions
+struct CGExp;
+struct CGMem;
+struct CGLea;
+struct CGCvt;
+struct CGUop;
+struct CGBop;
+struct CGJsr;
+struct CGVfn;
+struct CGScc;
+struct CGEsq;
+//leaf expressions
+struct CGFrm;
+struct CGTmp;
+struct CGLit;
+struct CGSym;
+struct CGDat;
+//private!
+struct CGReg;
+
+struct CGVisitor{
+ virtual CGStm *visit( CGStm *stm );
+ virtual CGExp *visit( CGExp *exp );
+};
+
+struct CGStm{
+ virtual ~CGStm()=0;
+
+ virtual CGNop *nop();
+ virtual CGXop *xop();
+ virtual CGRem *rem();
+ virtual CGAti *ati();
+ virtual CGAtd *atd();
+ virtual CGMov *mov();
+ virtual CGLab *lab();
+ virtual CGBra *bra();
+ virtual CGBcc *bcc();
+ virtual CGEva *eva();
+ virtual CGRet *ret();
+ virtual CGSeq *seq();
+
+ virtual CGStm *visit( CGVisitor &vis );
+};
+
+typedef std::vector<CGStm*> CGStmSeq;
+
+struct CGExp{
+ int type;
+
+ virtual ~CGExp()=0;
+
+ virtual CGMem *mem();
+ virtual CGLea *lea();
+ virtual CGCvt *cvt();
+ virtual CGUop *uop();
+ virtual CGBop *bop();
+ virtual CGJsr *jsr();
+ virtual CGVfn *vfn();
+ virtual CGScc *scc();
+ virtual CGEsq *esq();
+ virtual CGFrm *frm();
+ virtual CGTmp *tmp();
+ virtual CGLit *lit();
+ virtual CGSym *sym();
+ virtual CGDat *dat();
+ virtual CGReg *reg();
+
+ virtual CGExp *nonEsq();
+
+ virtual bool sideEffects();
+ virtual bool equals( CGExp *exp );
+ virtual CGExp *visit( CGVisitor &vis );
+
+ bool isint(){ return !isfloat(); }
+ bool isfloat(){ return type==CG_FLOAT32||type==CG_FLOAT64; }
+};
+
+struct CGNop : public CGStm{
+
+ CGNop *nop();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGXop : public CGStm{
+ int op;
+ CGReg *def;
+ CGExp *exp;
+
+ CGXop *xop();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGRem : public CGStm{
+ string comment;
+
+ CGRem *rem();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGAti : public CGStm{
+ CGMem *mem;
+
+ CGAti *ati();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGAtd : public CGStm{
+ CGMem *mem;
+ CGSym *sym;
+
+ CGAtd *atd();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGMov : public CGStm{
+ CGExp *lhs,*rhs;
+
+ CGMov *mov();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGLab : public CGStm{
+ CGSym *sym;
+
+ CGLab *lab();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGBra : public CGStm{
+ CGSym *sym;
+
+ CGBra *bra();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGBcc : public CGStm{
+ int cc;
+ CGExp *lhs,*rhs;
+ CGSym *sym;
+
+ CGBcc *bcc();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGEva : public CGStm{
+ CGExp *exp;
+
+ CGEva *eva();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGRet : public CGStm{
+ CGExp *exp;
+
+ CGRet *ret();
+
+ CGStm *visit( CGVisitor &vis );
+};
+
+struct CGSeq : public CGStm{
+ vector<CGStm*> stms;
+
+ CGSeq *seq();
+
+ CGStm *visit( CGVisitor &vis );
+
+ void push_back( CGStm *stm );
+ void push_front( CGStm *stm );
+};
+
+struct CGMem : public CGExp{
+ CGExp *exp;
+ int offset,flags;
+
+ CGMem *mem();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGLea : public CGExp{
+ CGExp *exp;
+
+ CGLea *lea();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGCvt : public CGExp{
+ CGExp *exp;
+
+ CGCvt *cvt();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGUop : public CGExp{
+ int op;
+ CGExp *exp;
+
+ CGUop *uop();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGBop : public CGExp{
+ int op;
+ CGExp *lhs,*rhs;
+
+ CGBop *bop();
+
+ bool commutes();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGJsr : public CGExp{
+ int call_conv;
+ CGExp *exp;
+ std::vector<CGExp*> args;
+
+ CGJsr *jsr();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGVfn : public CGExp{
+ CGExp *exp,*self;
+
+ CGVfn *vfn();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGScc : public CGExp{
+ int cc;
+ CGExp *lhs,*rhs;
+
+ CGScc *scc();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGEsq : public CGExp{
+ CGStm *lhs;
+ CGExp *rhs;
+
+ CGEsq *esq();
+
+ CGExp *nonEsq();
+
+ bool sideEffects();
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGFrm : public CGExp{
+ CGFrm *frm();
+
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGTmp : public CGExp{
+ string ident;
+ CGTmp *owner;
+
+ CGTmp *tmp();
+
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGReg : public CGExp{
+ int id,color;
+ CGReg *owner;
+
+ CGReg *reg();
+
+ bool equals( CGExp *e );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGLit : public CGExp{
+ int64 int_value;
+ double float_value;
+ bstring string_value;
+
+ CGLit *lit();
+
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGSym : public CGExp{
+ string value;
+ int linkage;
+
+ CGSym *sym();
+
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+};
+
+struct CGDat : public CGSym{
+ std::vector<CGExp*> exps;
+
+ CGDat *dat();
+
+ bool equals( CGExp *exp );
+ CGExp *visit( CGVisitor &vis );
+
+ void push_back( CGExp *exp );
+};
+
+struct CGFun : public CGExp{
+ int call_conv;
+ CGSym *sym;
+ CGExp *self;
+ std::vector<CGExp*> args;
+ std::vector<CGStm*> stms;
+};
+
+#endif
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgdebug.h"
+
+#include <typeinfo>
+
+static const char *ccSym( int cc ){
+ switch( cc ){
+ case CG_EQ:return "EQ";
+ case CG_NE:return "NE";
+ case CG_LT:return "LT";
+ case CG_GT:return "GT";
+ case CG_LE:return "LE";
+ case CG_GE:return "GE";
+ case CG_LTU:return "LTU";
+ case CG_GTU:return "GTU";
+ case CG_LEU:return "LEU";
+ case CG_GEU:return "GEU";
+ }
+ assert(0);
+ return 0;
+}
+
+static const char *uopSym( int op ){
+ return "UOP";
+}
+
+static const char *bopSym( int op ){
+ switch( op ){
+ case CG_ADD:return "add";
+ case CG_SUB:return "sub";
+ case CG_MUL:return "mul";
+ case CG_DIV:return "div";
+ case CG_MOD:return "mod";
+ case CG_AND:return "and";
+ case CG_ORL:return "orl";
+ case CG_XOR:return "xor";
+ case CG_SHL:return "shl";
+ case CG_SHR:return "shr";
+ case CG_SAR:return "sar";
+ }
+ assert(0);
+ return 0;
+}
+
+static const char *typeSym( int ty ){
+ switch( ty ){
+ case CG_PTR:return "PTR";
+ case CG_VOID:return "VOID";
+ case CG_INT8:return "INT8";
+ case CG_INT16:return "INT16";
+ case CG_INT32:return "INT32";
+ case CG_INT64:return "INT64";
+ case CG_FLOAT32:return "FLOAT32";
+ case CG_FLOAT64:return "FLOAT64";
+ case CG_CSTRING:return "CSTRING";
+ case CG_BSTRING:return "BSTRING";
+ }
+ assert(0);
+ return 0;
+}
+
+ostream &operator<<( ostream &o,CGStm *stm ){
+
+ if( !stm ) return o;
+
+ if( CGNop *t=stm->nop() ){
+ o<<"nop";
+ }else if( CGMov *t=stm->mov() ){
+ o<<"mov "<<t->lhs<<','<<t->rhs;
+ }else if( CGLab *t=stm->lab() ){
+ o<<"lab "<<t->sym;
+ }else if( CGBra *t=stm->bra() ){
+ o<<"bra "<<t->sym;
+ }else if( CGBcc *t=stm->bcc() ){
+ o<<"bcc "<<ccSym(t->cc)<<','<<t->lhs<<','<<t->rhs<<","<<t->sym;
+ }else if( CGRet *t=stm->ret() ){
+ o<<"ret ";if( t->exp ) o<<t->exp;
+ }else if( CGSeq *t=stm->seq() ){
+ int i;
+ o<<"seq ";
+ for( i=0;i<t->stms.size();++i ){
+ if( i ) o<<',';
+ o<<t->stms[i];
+ }
+ }else if( CGXop *t=stm->xop() ){
+ o<<"xop "<<t->op<<','<<t->exp;
+ }else if( CGRem *t=stm->rem() ){
+ o<<"rem "<<t->comment;
+ }else if( CGEva *t=stm->eva() ){
+ o<<"eva "<<t->exp;
+ }else if( CGAti *t=stm->ati() ){
+ o<<"ati "<<t->mem;
+ }else if( CGAtd *t=stm->atd() ){
+ o<<"atd "<<t->mem<<","<<t->sym;
+ }else{
+ o<<"STM: "<<typeid(*stm).name()<<endl;
+ assert(0);
+ }
+ return o;
+}
+
+ostream &operator<<( ostream &o,CGExp *exp ){
+
+ const char *ty=typeSym(exp->type);
+
+ if( CGMem *t=exp->mem() ){
+ o<<"mem("<<ty<<','<<t->exp<<','<<t->offset<<')';
+ }else if( CGLea *t=exp->lea() ){
+ o<<"lea("<<ty<<","<<t->exp<<')';
+ }else if( CGCvt *t=exp->cvt() ){
+ o<<"cvt("<<ty<<','<<t->exp<<')';
+ }else if( CGUop *t=exp->uop() ){
+ o<<uopSym(t->op)<<'('<<ty<<','<<t->exp<<')';
+ }else if( CGBop *t=exp->bop() ){
+ o<<bopSym(t->op)<<'('<<ty<<','<<t->lhs<<','<<t->rhs<<')';
+ }else if( CGJsr *t=exp->jsr() ){
+ o<<"jsr("<<ty<<','<<t->exp;
+ for( int k=0;k<t->args.size();++k ) o<<','<<t->args[k];
+ o<<')';
+ }else if( CGVfn *t=exp->vfn() ){
+ o<<"vfn("<<ty<<','<<t->exp<<','<<t->self<<')';
+ }else if( CGScc *t=exp->scc() ){
+ o<<"scc("<<ty<<','<<t->lhs<<','<<t->rhs<<')';
+ }else if( CGEsq *t=exp->esq() ){
+ o<<"esq("<<ty<<','<<t->lhs<<','<<t->rhs<<')';
+ }else if( CGReg *t=exp->reg() ){
+ o<<"reg("<<ty<<','<<t->id<<')';
+ }else if( CGTmp *t=exp->tmp() ){
+ o<<"tmp("<<ty<<','<<t->ident<<')';
+ }else if( CGLit *t=exp->lit() ){
+ if( t->isfloat() ) o<<ty<<' '<<t->float_value;
+ else o<<ty<<' '<<int(t->int_value);
+ }else if( CGSym *t=exp->sym() ){
+ o<<"sym("<<t->value<<")";
+ }else if( CGFrm *t=exp->frm() ){
+ o<<"frm";
+ }else{
+ assert(0);
+ }
+ return o;
+}
+
+ostream &operator<<( ostream &o,const CGStmSeq &seq ){
+ for( int k=0;k<seq.size();++k ){
+ o<<seq[k]<<endl;
+ }
+ return o;
+}
+
+ostream &operator<<( ostream &o,const CGAsmSeq &seq ){
+ CGAsm *as;
+ for( as=seq.begin;as!=seq.end;as=as->succ ){
+ if( as->stm ) o<<"\t;"<<as->stm<<endl;
+ if( as->assem ) o<<as->assem;
+ }
+ return o;
+}
+
+ostream &operator<<( ostream &o,const CGIntSet &t ){
+ CGIntSet::const_iterator it;
+ for( it=t.begin();it!=t.end();++it ) o<<' '<<*it;
+ return o;
+}
+
+ostream &operator<<( ostream &o,CGFlow *flow ){
+
+ CGBlockSeq &seq=flow->blocks;
+
+ CGBlockCIter it;
+
+ //enumerate blocks
+ map<CGBlock*,int> blk_map;
+ for( it=seq.begin();it!=seq.end();++it ){
+ blk_map[*it]=blk_map.size();
+ }
+
+ for( it=seq.begin();it!=seq.end();++it ){
+ CGBlock *blk=*it;
+ CGBlockCIter t_it;
+ o<<"\t;---block "<<blk_map[blk]<<"---"<<endl;
+ o<<"\t;use:"<<blk->use<<endl;
+ o<<"\t;def:"<<blk->def<<endl;
+ o<<"\t;live_in:"<<blk->live_in<<endl;
+ o<<"\t;live_out:"<<blk->live_out<<endl;
+
+ o<<"\t;succ:";
+ for( t_it=blk->succ.begin();t_it!=blk->succ.end();++t_it ) o<<' '<<blk_map[*t_it];
+ o<<endl;
+
+ o<<"\t;pred:";
+ for( t_it=blk->pred.begin();t_it!=blk->pred.end();++t_it ) o<<' '<<blk_map[*t_it];
+ o<<endl;
+
+ set<CGBlock*>::iterator d_it;
+
+ o<<"\t;dom:";
+ for( d_it=blk->dom.begin();d_it!=blk->dom.end();++d_it ){
+ o<<' '<<blk_map[*d_it];
+ }
+ o<<endl;
+
+ /*
+ o<<"\t;loops:";
+ for( d_it=blk->loops.begin();d_it!=blk->loops.end();++d_it ){
+ o<<' '<<blk_map[*d_it];
+ }
+ o<<endl;
+ */
+
+ o<<"\t;loop_level:"<<blk->loop_level<<endl;
+
+ o<<endl;
+ CGAsm *as=blk->begin;
+ while( as!=blk->end ){
+ if( as->stm ) o<<"\t;"<<as->stm<<endl;
+ if( as->def.size() ) o<<"\t;def="<<as->def<<endl;
+ if( as->use.size() ) o<<"\t;use="<<as->use<<endl;
+ if( as->assem ) o<<as->assem;
+ as=as->succ;
+ }
+
+ o<<endl;
+ }
+
+ return o;
+}
+
+ostream &operator<<( ostream &o,CGFun *fun ){
+ for( int k=0;k<fun->stms.size();++k ){
+ o<<fun->stms[k]<<endl;
+ }
+ return o;
+}
+
+bool cgVerify( ostream &o,CGExp *exp ){
+ return true;
+}
+
+bool cgVerify( ostream &o,CGStm *stm ){
+ return true;
+}
+
+bool cgVerify( ostream &o,CGFun *fun ){
+ return true;
+}
--- /dev/null
+
+#ifndef CGDEBUG_H
+#define CGDEBUG_H
+
+#include "cgflow.h"
+
+bool cgVerify( std::ostream &o,CGExp *exp );
+bool cgVerify( std::ostream &o,CGStm *stm );
+bool cgVerify( std::ostream &o,CGFun *fun );
+
+std::ostream &operator<<( std::ostream &out,CGStm *stm );
+std::ostream &operator<<( std::ostream &out,CGExp *exp );
+std::ostream &operator<<( std::ostream &out,CGFun *fun );
+
+std::ostream &operator<<( std::ostream &out,CGFlow *flow );
+
+std::ostream &operator<<( std::ostream &out,const CGStmSeq &seq );
+std::ostream &operator<<( std::ostream &out,const CGAsmSeq &seq );
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgframe_x86.h"
+#include "cgutil.h"
+#include "cgdebug.h"
+
+//#define _DEBUG_FPSTACK
+
+static CGFrame_X86 *frame;
+static char tmpbuf8[256],tmpbuf16[256],tmpbuf32[256],*buf,*buf_a,*buf_b,*out;
+
+struct FPStack;
+
+typedef set<CGBlock*> BlockSet;
+typedef map<CGBlock*,FPStack*> StackMap;
+
+static BlockSet blocks_todo;
+static StackMap stack_map;
+
+static void emit( const char *fmt,... ){
+ va_list args;
+ va_start( args,fmt );
+ vsprintf( out,fmt,args );
+ out+=strlen(out);
+}
+
+struct FPStack{
+
+ int regs[8],stack[8],sp;
+
+ FPStack( int live ):sp(8){
+ memset( regs,-1,sizeof(regs) );
+ memset( stack,0,sizeof(stack) );
+ for( int k=0;k<8;++k ){
+ if( live & (1<<k) ) push(k);
+ }
+ }
+
+ FPStack( FPStack *st ):sp(st->sp){
+ memcpy( regs,st->regs,sizeof(regs) );
+ memcpy( stack,st->stack,sizeof(stack) );
+ }
+
+ int liveMask(){
+ int n=0;
+ for( int k=sp;k<8;++k ) n|=1<<stack[k];
+ return n;
+ }
+
+ bool equals( FPStack *st ){
+ if( sp!=st->sp ) return false;
+ for( int k=sp;k<8;++k ){
+ if( stack[k]!=st->stack[k] ) return false;
+ }
+ return true;
+ }
+
+ int top(){
+ return stack[sp];
+ }
+
+ void pop(){
+ int r=stack[sp];
+ regs[r]=-1;
+ ++sp;
+ }
+
+ void push( int r ){
+ --sp;
+ regs[r]=sp;
+ stack[sp]=r;
+ }
+
+ void swap( int rd,int rs ){
+ assert(regs[rs]>=0 && regs[rd]>=0);
+ std::swap( stack[regs[rs]],stack[regs[rd]] );
+ std::swap( regs[rs],regs[rd] );
+ }
+
+ int stoff( int r ){
+ return regs[r]-sp;
+ }
+
+ void fpop(){
+ emit( "\tfstp\tst0\n" );
+ pop();
+ }
+
+ void fxch( int r ){
+ if( r==top() ) return;
+ emit( "\tfxch\tst%i\n",stoff(r) );
+ swap( r,top() );
+ }
+
+ void fpop( int r ){
+ if( regs[r]<0 ) return;
+ fxch(r);
+ fpop();
+ }
+
+ void debug(){
+ for( int k=0;k<8;++k ){
+ if( k<sp ) cout<<"-- ";
+ else cout<<'f'<<stack[k]<<' ';
+ }
+ cout<<" sp:"<<sp<<endl;
+ }
+
+
+ void fdebug(){
+//#ifdef _DEBUG_FPSTACK
+ emit( "\t;" );
+ for( int k=0;k<8;++k ){
+ if( k<sp ) emit( "-- " );
+ else emit( "f%i ",stack[k] );
+ }
+ emit( "\n" );
+//#endif
+ }
+
+ void fadjust( int live ){
+ for( int k=sp;k<8;++k ){
+ if( !(live & (1<<stack[k])) ) fpop( stack[k] );
+ }
+ }
+
+ void fadjust( FPStack *st ){
+#ifdef _DEBUG_FPSTACK
+ emit( "\t;fadjust...\n" );
+#endif
+
+ for( int t_sp=7;t_sp>=st->sp;--t_sp ){
+
+ int t=top();
+
+ for( ;st->regs[t]==-1;t=top() ) fpop();
+
+ int rs=stack[t_sp];
+ int rd=st->stack[t_sp];
+
+ if( rs==rd ){
+
+ }else if( st->regs[rs]==-1 ){
+ fxch( rd );
+ emit( "\tfstp\tst%i\n",t_sp-sp );
+ stack[regs[rd]=t_sp]=rd;
+ pop();
+ }else{
+ fxch( rd );
+ fxch( rs );
+ }
+ }
+ while( sp<st->sp ) fpop();
+ }
+
+ void fcopy( int rd,int rs,int live ){
+
+ if( rd==rs || !(live&(1<<rd)) ){
+ if( !(live&(1<<rd)) ) fpop(rd);
+ if( !(live&(1<<rs)) ) fpop(rs);
+ return;
+ }
+
+ if( live&(1<<rs) ){
+ if( regs[rd]>=0 ){
+ fxch(rs);
+ emit( "\tfst\tst%i\n",stoff(rd) );
+ }else{
+ emit( "\tfld\tst%i\n",stoff(rs) );
+ push(rd);
+ }
+ }else{
+ if( regs[rd]>=0 ){
+ fxch(rs);
+ emit( "\tfstp\tst%i\n",stoff(rd) );
+ pop();
+ }else{
+ stack[regs[rs]]=rd;
+ regs[rd]=regs[rs];
+ regs[rs]=-1;
+ }
+ }
+ }
+
+
+ void fload( int rd,double val,int live ){
+
+ if( !(live&(1<<rd)) ){
+ fpop(rd);
+ return;
+ }
+
+ if( val==0.0 ) emit( "\tfldz\n" );
+ else if( val==1.0 ) emit( "\tfld1\n" );
+ else assert(0);
+
+ if( regs[rd]>=0 ){
+ emit( "\tfstp\tst%i\n",stoff(rd)+1 );
+ }else{
+ push(rd);
+ }
+ }
+
+ void fload( int rd,const char *ea,const char *op,int live ){
+ if( live&(1<<rd) ){
+ emit( "\t%s\t%s\n",op,ea );
+ if( regs[rd]>=0 ){
+ emit( "\tfstp\tst%i\n",stoff(rd)+1 );
+ }else{
+ push(rd);
+ }
+ }else{
+ fpop(rd);
+ }
+ }
+
+ void fstore( int rs,const char *ea,const char *op,int live ){
+ fxch( rs );
+ if( live&(1<<rs) ){
+ emit( "\t%s\t%s\n",op,ea );
+ }else{
+ emit( "\t%sp\t%s\n",op,ea );
+ pop();
+ }
+ }
+
+ void funiop( int rd,const char *op,int live ){
+ if( !(live&(1<<rd)) ){
+ fpop(rd);
+ return;
+ }
+ fxch(rd);
+ emit( "\t%s\n",op );
+ }
+
+ void fbinop( int rd,int rs,const char *op,int live ){
+ if( !(live&(1<<rd)) ){
+ fpop(rd);
+ if( !(live&(1<<rs)) ) fpop(rs);
+ return;
+ }
+ if( live&(1<<rs) ){
+ if( top()==rs ){
+ emit( "\t%s\tst%i,st0\n",op,stoff(rd) );
+ }else{
+ fxch(rd);
+ emit( "\t%s\tst0,st%i\n",op,stoff(rs) );
+ }
+ }else{
+ if( top()==rd ){
+ const char *r_op=op;
+ if( !strcmp(op,"fsub") ) r_op="fsubr";
+ else if( !strcmp(op,"fdiv") ) r_op="fdivr";
+ emit( "\t%sp\tst%i,st0\n",r_op,stoff(rs) );
+ stack[regs[rs]]=rd;
+ regs[rd]=regs[rs];
+ regs[rs]=-1;
+ ++sp;
+ }else{
+ fxch(rs);
+ emit( "\t%sp\tst%i,st0\n",op,stoff(rd) );
+ pop();
+ }
+ }
+ }
+
+ void fbinop( int rd,const char *ea,const char *op,int live ){
+ if( !(live&(1<<rd)) ){
+ fpop(rd);
+ return;
+ }
+ fxch(rd);
+ emit( "\t%s\t%s\n",op,ea );
+ }
+
+ void fcomp( int rd,int rs,int live ){
+ fxch(rd);
+ if( live&(1<<rd) ){
+ emit( "\tfucom\tst%i\n",stoff(rs) );
+ if( !(live&(1<<rs)) ) fpop(rs);
+ }else{
+ if( live&(1<<rs) ){
+ emit( "\tfucomp\tst%i\n",stoff(rs) );
+ pop();
+ }else if( stoff(rs)==1 ){
+ emit( "\tfucompp\n" );
+ pop();
+ pop();
+ }else{
+ emit( "\tfucomp\tst%i\n",stoff(rs) );
+ pop();
+ fpop(rs);
+ }
+ }
+ emit( "\tfnstsw\tax\n" );
+ emit( "\tsahf\n" );
+ }
+};
+
+static int liveMask( const CGIntSet &t ){
+ int live=0;
+ CGIntCIter it;
+ for( it=t.begin();it!=t.end();++it ){
+ CGReg *r=frame->regs[*it];
+ if( r->isfloat() ){
+ assert(r->color>=0);
+ live|=(1<<r->color);
+ }
+ }
+ return live;
+}
+
+static void adjustStack( FPStack *st,CGBlock *blk ){
+ StackMap::iterator it=stack_map.find(blk);
+
+ if( it!=stack_map.end() ){
+ st->fadjust( it->second );
+ return;
+ }
+
+ st->fadjust( liveMask(blk->live_in) );
+ stack_map.insert( make_pair(blk,new FPStack(st)) );
+ blocks_todo.insert( blk );
+}
+
+static const char *op1( CGAsm *as ){
+ static char buf[256];
+
+ const char *b=strchr( as->assem+1,'\t' );
+ assert(b);
+ ++b;
+
+ const char *e=strchr( as->assem,',' );
+ if( !e ) e=b+strlen(b);
+
+ int sz=e-b;
+ memcpy(buf,b,sz);
+ buf[sz]=0;
+ return buf;
+}
+
+static const char *op2( CGAsm *as ){
+ static char buf[256];
+
+ const char *b=strchr( as->assem,',' );
+ assert(b);
+ ++b;
+
+ const char *e=strchr( b,'\n' );
+ assert(e);
+
+ int sz=e-b;
+ memcpy(buf,b,sz);
+ buf[sz]=0;
+ return buf;
+}
+
+static void allocTmp32(){
+ if( tmpbuf32[0] ) return;
+ CGMem *m=frame->allocLocal(CG_INT32);
+ sprintf( tmpbuf8,"byte [ebp+%i]",m->offset );
+ sprintf( tmpbuf16,"word [ebp+%i]",m->offset );
+ sprintf( tmpbuf32,"dword [ebp+%i]",m->offset );
+}
+
+static bool fixXop( CGAsm *as,CGXop *op,FPStack *st,int live ){
+
+ CGExp *exp=op->exp;
+
+ if( op->op==CGFrame_X86::XOP_PUSH4 ){
+ //push dword
+ if( exp->isint() || exp->mem() ) return false;
+ int rs=exp->reg()->color;
+ emit( "\tsub\tesp,4\n" );
+ st->fstore( rs,"dword [esp]","fst",live );
+ return true;
+ }
+ if( op->op==CGFrame_X86::XOP_PUSH8 ){
+ //push qword
+ if( exp->isint() ) return false;
+ assert( !exp->mem() );
+ int rs=exp->reg()->color;
+ emit( "\tsub\tesp,8\n" );
+ st->fstore( rs,"qword [esp]","fst",live );
+ return true;
+ }
+ return false;
+}
+
+static bool fixEva( CGAsm *as,CGEva *ev,FPStack *st,int live ){
+
+ CGExp *exp=ev->exp;
+
+ if( CGJsr *t=exp->jsr() ){
+ if( !exp->isfloat() ) return false;
+ if( !live ){
+ emit(as->assem);
+ emit("\tfstp\tst0\n");
+ return true;
+ }else if( live==1 ){
+ if( st->regs[0]<0 ) st->push(0);
+ return false;
+ }
+ cout<<"Invalid FP stack state after FP jsr"<<endl;
+ return false;
+ }
+ return false;
+}
+
+static bool fixMov( CGAsm *as,CGMov *mv,FPStack *st,int live ){
+
+ CGExp *lhs=mv->lhs;
+ CGExp *rhs=mv->rhs;
+
+ if( CGCvt *t=rhs->cvt() ){
+ if( lhs->isfloat() ){
+ if( t->exp->isfloat() ){
+ //float to float
+ st->fcopy( lhs->reg()->color,t->exp->reg()->color,live );
+ return true;
+ }
+ //int to float
+ allocTmp32();
+ int rd=lhs->reg()->color;
+ emit( "\tmov\t%s,%s\n",tmpbuf32,op2(as) );
+ st->fload( rd,tmpbuf32,"fild",live );
+ return true;
+ }else if( t->exp->isfloat() ){
+ //float to int
+ allocTmp32();
+ int rs=t->exp->reg()->color;
+ st->fstore( rs,tmpbuf32,"fist",live );
+ if( lhs->type==CG_INT8 ){
+ emit( "\tmovzx\t%s,%s\n",op1(as),tmpbuf8 );
+ }else if( lhs->type==CG_INT16 ){
+ emit( "\tmovzx\t%s,%s\n",op1(as),tmpbuf16 );
+ }else{
+ emit( "\tmov\t%s,%s\n",op1(as),tmpbuf32 );
+ }
+ return true;
+ }
+ return false;
+ }else if( CGScc *t=rhs->scc() ){
+ if( !t->lhs->isfloat() ) return false;
+ int rd=t->lhs->reg()->color;
+ int rs=t->rhs->reg()->color;
+ st->fcomp( rd,rs,live );
+ const char *op;
+ switch( t->cc ){
+ case CG_EQ:op="z";break;
+ case CG_NE:op="nz";break;
+ case CG_LT:op="b";break;
+ case CG_GT:op="a";break;
+ case CG_LE:op="be";break;
+ case CG_GE:op="ae";break;
+ }
+ emit( "\tset%s\tal\n",op );
+ emit( "\tmovzx\teax,al\n" );
+ return true;
+ }
+
+ if( lhs->isint() && rhs->isint() ) return false;
+ assert( lhs->isfloat() && rhs->isfloat() );
+
+ if( lhs->reg() && rhs->reg() ){
+ st->fcopy( lhs->reg()->color,rhs->reg()->color,live );
+ return true;
+ }
+ if( CGJsr *t=rhs->jsr() ){
+ if( !live ){
+ emit(as->assem);
+ emit("\tfstp\tst0\n");
+ return true;
+ }else if( live==1 ){
+ if( st->regs[0]<0 ) st->push(0);
+ return false;
+ }
+ cout<<"Invalid FP stack state after FP jsr"<<endl;
+ return false;
+/*
+ emit(as->assem);
+ if( live&1 ){
+ if( st->regs[0]<0 ) st->push(0);
+ }else if( st->regs[0]>=0 ){
+ st->fpop();
+ }
+ return true;
+ */
+ }
+ if( CGMem *t=rhs->mem() ){
+ int rd=lhs->reg()->color;
+ st->fload( rd,op2(as),"fld",live );
+ return true;
+ }
+ if( CGMem *t=lhs->mem() ){
+ int rs=rhs->reg()->color;
+ st->fstore( rs,op1(as),"fst",live );
+ return true;
+ }
+ if( CGUop *t=rhs->uop() ){
+ int rd=lhs->reg()->color;
+ const char *op;
+ switch( t->op ){
+ case CG_NEG:op="fchs";break;
+ default:assert(0);
+ }
+ st->funiop( rd,op,live );
+ return true;
+ }
+ if( CGBop *t=rhs->bop() ){
+ int rd=lhs->reg()->color;
+ const char *op;
+ switch( t->op ){
+ case CG_ADD:op="fadd";break;
+ case CG_SUB:op="fsub";break;
+ case CG_MUL:op="fmul";break;
+ case CG_DIV:op="fdiv";break;
+ default:assert(0);
+ }
+ if( CGReg *r=t->rhs->reg() ){
+ st->fbinop( rd,r->color,op,live );
+ }else{
+ st->fbinop( rd,op2(as),op,live );
+ }
+ return true;
+ }
+ if( CGLit *t=rhs->lit() ){
+ int rd=lhs->reg()->color;
+ st->fload( rd,t->float_value,live );
+ return true;
+ }
+ assert(0);
+ return false;
+}
+
+static void fix( CGBlock *blk ){
+
+ if( blk->begin==blk->end ) return;
+
+ vector<int> live_stack;
+ int live=liveMask( blk->live_out );
+
+ CGAsm *as=blk->end;
+ while( as!=blk->begin ){
+ as=as->pred;
+
+ live_stack.push_back( live );
+
+ live&=~liveMask(as->def);
+ live|=liveMask(as->use);
+ }
+
+ assert( stack_map.count(blk) );
+ FPStack *st=new FPStack( stack_map[blk] );
+ assert( st->liveMask()==live );
+
+ for( as=blk->begin;as!=blk->end;as=as->succ ){
+
+ live=live_stack.back();
+ live_stack.pop_back();
+
+ *(out=buf)=0;
+
+ bool fix=false;
+
+ if( CGMov *t=as->stm->mov() ){
+ fix=fixMov( as,t,st,live );
+ }else if( CGXop *t=as->stm->xop() ){
+ fix=fixXop( as,t,st,live );
+ }else if( CGEva *t=as->stm->eva() ){
+ fix=fixEva( as,t,st,live );
+ }
+
+ if( fix ) as->assem=strdup(buf);
+ }
+
+ as=as->pred;
+
+ buf_a[0]=0;
+ CGBlock *blk_a=blk->succ.size()>0 ? blk->succ[0] : 0;
+ if( blk_a ){
+ out=buf_a;
+ adjustStack( new FPStack(st),blk_a );
+ }
+
+ buf_b[0]=0;
+ CGBlock *blk_b=blk->succ.size()>1 ? blk->succ[1] : 0;
+ if( blk_b ){
+ assert( as->stm->bcc() );
+ out=buf_b;
+ adjustStack( new FPStack(st),blk_b );
+ }
+
+ if( !buf_a[0] && !buf_b[0] ) return;
+
+ *(out=buf)=0;
+
+ assert( blk_a );
+
+ if( !blk_b ){
+
+ if( as->stm->bra() ){
+ emit( buf_a );
+ emit( as->assem );
+ }else{
+ emit( as->assem );
+ emit( buf_a );
+ }
+
+ }else if( !buf_b[0] ){
+
+ emit( as->assem );
+ emit( buf_a );
+
+ }else{
+
+ CGBcc *t=as->stm->bcc();
+
+ CGSym *skip=CG::sym();
+
+ const char *cc=CGFrame_X86::x86cc( CG::swapcc(t->cc) );
+
+ //find the jmp
+ char *p=strstr( as->assem,"\tj" );assert(p);
+
+ //cmp...
+ memcpy( out,as->assem,p-as->assem );out+=p-as->assem;
+
+ //new jmp
+ emit( "\tj%s\t%s\n",cc,skip->value.c_str() );
+
+ //normalize bra block
+ emit( buf_b );
+
+ //bra to block
+ emit( "\tjmp\t%s\n",t->sym->value.c_str() );
+
+ //our new symbol!
+ emit( "%s:\n",skip->value.c_str() );
+
+ emit( buf_a );
+ }
+
+ as->assem=strdup(buf);
+}
+
+void CGFrame_X86::fixFp(){
+
+ if( !flow->blocks.size() ) return;
+
+ ::frame=this;
+
+ tmpbuf32[0]=0;
+ buf=new char[1024];
+ buf_a=new char[1024];
+ buf_b=new char[1024];
+
+ CGBlock *blk=*flow->blocks.begin();
+
+ stack_map.clear();
+ stack_map.insert( make_pair(blk,new FPStack(0)) );
+
+ blocks_todo.clear();
+ blocks_todo.insert( blk );
+
+ while( blocks_todo.size() ){
+ BlockSet::iterator it=blocks_todo.begin();
+ CGBlock *blk=*it;
+ blocks_todo.erase(it);
+ fix(blk);
+ }
+
+ blocks_todo.clear();
+ stack_map.clear();
+
+ delete[] buf_b;
+ delete[] buf_a;
+ delete[] buf;
+}
--- /dev/null
+
+#ifndef CGFIXFP_X86_H
+#define CGFIXFP_X86_H
+
+#endif
+
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgflow.h"
+#include "cgutil.h"
+#include "cgdebug.h"
+
+//#define _DEBUG_FLOW
+
+static set<CGBlock*> reachable;
+
+static void findReachable( CGBlock *blk ){
+ if( !reachable.insert(blk).second ) return;
+ CGBlockIter it;
+ for( it=blk->succ.begin();it!=blk->succ.end();++it ){
+ findReachable(*it);
+ }
+}
+
+//******************* Build flow ******************
+CGBlock *CGFlow::block( CGAsm *as,CGBlock *p ){
+ CGBlock *b=new CGBlock;
+ b->begin=b->end=as;
+ blocks.push_back(b);
+ if( !p ) return b;
+ p->succ.push_back(b);
+ b->pred.push_back(p);
+ return b;
+}
+
+void CGFlow::buildFlow(){
+
+ CGAsm *as;
+ blocks.clear();
+ map<CGSym*,CGBlock*> lab_map;
+ map<CGBlock*,CGSym*> bra_map;
+
+#ifdef _DEBUG_FLOW
+ cout<<"CGFlow::buildFlow()"<<endl;
+#endif
+
+ //make sure there's a label at the start
+ if( !assem.begin->stm->lab() ){
+ assem.insert( new CGAsm(CG::lab(),""),assem.begin );
+ }
+
+ //ensure there's a LAB after each BRA/BCC/RET
+ for( as=assem.begin;as!=assem.end;as=as->succ ){
+ CGStm *st=as->stm;
+ if( !st->bra() && !st->bcc() && !st->ret() ) continue;
+ if( as->succ->stm->lab() ) continue;
+ as=assem.insert( new CGAsm(CG::lab(),""),as->succ );
+ }
+
+ as=assem.begin;
+ CGBlock *b=block(as,0);
+ while( as!=assem.end ){
+
+ CGStm *st=as->stm;
+
+ if( CGLab *t=st->lab() ){
+ if( as!=b->begin ){
+ b->end=as;
+ b=block(as,b);
+ }
+ lab_map[t->sym]=b;
+ as=as->succ;
+ }else if( CGBra *t=st->bra() ){
+ bra_map[b]=t->sym;
+ as=as->succ;
+ b->end=as;
+ b=block(as,0);
+ }else if( CGBcc *t=st->bcc() ){
+ bra_map[b]=t->sym;
+ as=as->succ;
+ b->end=as;
+ b=block(as,b);
+ }else if( CGRet *t=st->ret() ){
+ as=as->succ;
+ b->end=as;
+ b=block(as,0);
+ }else{
+ as=as->succ;
+ }
+ }
+ b->end=as;
+
+ //patch bras
+ map<CGBlock*,CGSym*>::iterator it;
+ for( it=bra_map.begin();it!=bra_map.end();++it ){
+ CGBlock *src=it->first;
+ if( !lab_map.count(it->second) ) continue;
+ CGBlock *dst=lab_map[it->second];
+ src->succ.push_back( dst );
+ dst->pred.push_back( src );
+ }
+
+ //find reachable blocks
+ reachable.clear();
+ findReachable( *blocks.begin() );
+
+ CGBlockIter blk_it=blocks.begin();
+ for( ++blk_it;blk_it!=blocks.end(); ){
+
+ //reachable?
+ CGBlock *blk=*blk_it;
+ if( reachable.count(blk) ){
+ ++blk_it;
+ continue;
+ }
+
+ //erase assem
+ CGAsm *as=blk->begin;
+ while( as!=blk->end ) as=assem.erase(as);
+ (*(blk_it-1))->end=as;
+
+ //erase block
+ blk_it=blocks.erase( blk_it );
+ }
+}
+
+//***************** Loop detection ****************
+
+static void eraseDom( CGBlock *blk,CGBlock *dom ){
+
+ if( blk==dom ) return;
+
+ if( !blk->dom.insert(dom).second ) return;
+
+ CGBlockIter it;
+ for( it=blk->succ.begin();it!=blk->succ.end();++it ){
+ eraseDom( *it,dom );
+ }
+}
+
+static void insertLoop( CGBlock *blk,CGBlock *head ){
+
+ if( !head->loops.insert( blk ).second ) return;
+
+ CGBlockIter it;
+ for( it=blk->pred.begin();it!=blk->pred.end();++it ){
+ insertLoop( *it,head );
+ }
+}
+
+void CGFlow::findLoops(){
+
+#ifdef _DEBUG_FLOW
+ cout<<"CGFlow::findLoops() - blocks="<<blocks.size()<<endl;
+#endif
+
+// cout<<"findLoops blocks="<<blocks.size()<<endl;
+
+ int k;
+ for( k=0;k<blocks.size();++k ){
+ blocks[k]->dom.clear();
+ blocks[k]->loops.clear();
+ blocks[k]->loop_level=0;
+ }
+
+ if( blocks.size()>1000 ) return;
+
+// cout<<"EraseDom"<<endl;
+
+ for( k=0;k<blocks.size();++k ){
+ eraseDom( blocks[0],blocks[k] );
+ }
+
+// cout<<"Find back edges"<<endl;
+
+ //find back edges
+ for( k=0;k<blocks.size();++k ){
+ CGBlock *blk=blocks[k];
+
+ CGBlockIter it;
+ for( it=blk->succ.begin();it!=blk->succ.end();++it ){
+ CGBlock *head=*it;
+ if( blk->dom.count(head) ) continue;
+ head->loops.insert( head );
+ insertLoop( blk,head );
+ }
+ }
+
+// cout<<"Creating loop_level"<<endl;
+
+ //create loop_level
+ for( k=0;k<blocks.size();++k ){
+ CGBlock *blk=blocks[k];
+
+ set<CGBlock*>::iterator it;
+ for( it=blk->loops.begin();it!=blk->loops.end();++it ){
+ ++(*it)->loop_level;
+ }
+ }
+}
+
+//*************** liveness analysis ***************
+static void liveIn( CGBlock *blk,int n ){
+
+ if( !blk->live_in.insert( n ) ) return;
+
+ CGBlockIter it;
+ for( it=blk->pred.begin();it!=blk->pred.end();++it ){
+ CGBlock *t=*it;
+
+ if( t->live_out.insert(n) && !t->def.count(n) ) liveIn( t,n );
+ }
+}
+
+void CGFlow::liveness(){
+
+#ifdef _DEBUG_FLOW
+ cout<<"CGFlow::liveness()"<<endl;
+#endif
+
+ CGBlockIter blk_it;
+ for( blk_it=blocks.begin();blk_it!=blocks.end();++blk_it ){
+ CGBlock *blk=*blk_it;
+
+ blk->use.clear();
+ blk->def.clear();
+ blk->live_in.clear();
+ blk->live_out.clear();
+
+ CGAsm *as;
+
+ for( as=blk->begin;as!=blk->end;as=as->succ ){
+
+ blk->use.xinsert( as->use,blk->def );
+ blk->def.xinsert( as->def,blk->use );
+ }
+ }
+
+ for( blk_it=blocks.begin();blk_it!=blocks.end();++blk_it ){
+ CGBlock *blk=*blk_it;
+
+ CGIntCIter it;
+ for( it=blk->use.begin();it!=blk->use.end();++it ){
+ liveIn( blk,*it );
+ }
+ }
+}
+
+//***************** Constructor *******************
+static vector<CGFlow*> _flows;
+
+CGFlow::CGFlow( CGAsmSeq &t_assem ):assem(t_assem){
+ buildFlow();
+ findLoops();
+ _flows.push_back( this );
+}
+
+CGFlow::~CGFlow(){
+ for( int k=0;k<blocks.size();++k ){
+ delete blocks[k];
+ }
+}
--- /dev/null
+
+#ifndef CGFLOW_H
+#define CGFLOW_H
+
+#include "cgblock.h"
+
+struct CGFlow{
+ CGAsmSeq &assem;
+ CGBlockSeq blocks;
+
+ CGFlow( CGAsmSeq &assem );
+ virtual ~CGFlow();
+
+ void liveness();
+
+private:
+ void buildFlow();
+ void findLoops();
+ CGBlock *block( CGAsm *as,CGBlock *p );
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgframe.h"
+#include "cgallocregs.h"
+#include "cgutil.h"
+#include "cgdebug.h"
+#include "cgint64.h"
+
+typedef map<string,CGExp*> IdExpMap;
+
+CGFrame::CGFrame( CGFun *_fun ):fun(_fun),flow(0),int64ret(0){
+ asm_it=assem.end;
+ big_endian=!(little_endian=env_config.count("x86")?true:false);
+}
+
+CGFrame::~CGFrame(){
+ deleteFlow();
+}
+
+CGMem *CGFrame::int64el( CGMem *i64,int n ){
+ CGMem *m=CG::mem(CG_INT32,i64->exp,i64->offset+n);
+ m->flags=i64->flags;
+ return m;
+}
+
+CGMem *CGFrame::int64lo( CGMem *i64 ){
+ return int64el( i64,big_endian ? 4 : 0 );
+}
+
+CGMem *CGFrame::int64hi( CGMem *i64 ){
+ return int64el( i64,big_endian ? 0 : 4 );
+}
+
+//****************** Linearize ********************
+struct CGLinearizer : public CGVisitor{
+ CGFrame *frame;
+
+ CGLinearizer( CGFrame *f ):frame(f){}
+
+ CGStm *visit( CGStm *stm ){
+ if( stm->nop() || stm->seq() ) return stm;
+ frame->fun->stms.push_back(stm);
+ return stm;
+ }
+
+ CGExp *visit( CGExp *exp ){
+
+ if( CGEsq *t=exp->esq() ) return t->rhs;
+
+ if( exp->type==CG_INT64 ) return exp;
+
+ if( CGCvt *t=exp->cvt() ){
+ if( t->isint() && t->exp->isfloat() ){
+ if( env_config.count("x86") ){
+ exp=CG::cvt(t->type,CG::jsr(CG_INT32,"bbFloatToInt",CG::cvt(CG_FLOAT64,t->exp)));
+ }
+ }
+ }else if( CGUop *t=exp->uop() ){
+ string iop,fop;
+ switch( t->op ){
+ case CG_ABS:iop="bbIntAbs";fop="bbFloatAbs";break;
+ case CG_SGN:iop="bbIntSgn";fop="bbFloatSgn";break;
+ }
+ if( t->isint() && iop.size() ){
+ exp=CG::cvt(t->type,CG::jsr(CG_INT32,iop,CG::cvt(CG_INT32,t->exp)));
+ }else if( t->isfloat() && fop.size() ){
+ exp=CG::cvt(t->type,CG::jsr(CG_FLOAT64,fop,CG::cvt(CG_FLOAT64,t->exp)));
+ }
+ }else if( CGBop *t=exp->bop() ){
+ string iop,fop;
+ switch( t->op ){
+ case CG_MOD:fop="bbFloatMod";break;
+ case CG_MIN:iop="bbIntMin";fop="bbFloatMin";break;
+ case CG_MAX:iop="bbIntMax";fop="bbFloatMax";break;
+ }
+ if( t->isint() && iop.size() ){
+ exp=CG::cvt(t->type,CG::jsr(CG_INT32,iop,CG::cvt(CG_INT32,t->lhs),CG::cvt(CG_INT32,t->rhs)));
+ }else if( t->isfloat() && fop.size() ){
+ exp=CG::cvt(t->type,CG::jsr(CG_FLOAT64,fop,CG::cvt(CG_FLOAT64,t->lhs),CG::cvt(CG_FLOAT64,t->rhs)));
+ }
+ }
+ return exp;
+ }
+};
+
+void CGFrame::linearize(){
+
+ CGFun *in=fun;
+ fun=CG::fun( in->type,in->call_conv,in->sym,in->self );
+
+ if( int64ret ) fun->args.push_back( int64ret );
+
+ int k;
+ for( k=0;k<in->args.size();++k ){
+ CGExp *arg=in->args[k];
+ if( arg->type!=CG_INT64 ){
+ fun->args.push_back( arg );
+ continue;
+ }
+ assert( arg->mem() );
+ fun->args.push_back( int64el(arg->mem(),0) );
+ fun->args.push_back( int64el(arg->mem(),4) );
+ }
+
+ CGLinearizer vis( this );
+
+ for( k=0;k<in->stms.size();++k ) in->stms[k]->visit( vis );
+}
+
+//**************** Fix Symbols ********************
+struct CGSymFixer : public CGVisitor{
+ CGFrame *frame;
+
+ map<CGExp*,CGExp*> done;
+
+ CGSymFixer( CGFrame *f ):frame(f){}
+
+ CGExp *visit( CGExp *exp ){
+
+ CGSym *t=exp->sym();
+ if( !t || t->linkage==CG_INTERNAL ) return exp;
+
+ map<CGExp*,CGExp*>::iterator it=done.find(t);
+ if( it!=done.end() ) return it->second;
+
+ string id=frame->fixSym( t->value );
+
+ if( id==t->value ){
+ exp=t;
+ }else if( CGDat *d=exp->dat() ){
+ CGDat *t;
+ if( d->linkage==CG_INTERNAL ) t=CG::dat();
+ else t=CG::dat(id);
+ t->exps=d->exps;
+ exp=t;
+ }else{
+ exp=CG::sym(id,t->linkage);
+ }
+
+ done.insert( make_pair(t,exp) );
+ return exp;
+ }
+};
+
+void CGFrame::fixSymbols(){
+
+ CGSymFixer vis( this );
+
+ fun=CG::visitFun( fun,vis );
+}
+
+//************* Find Escaping Tmps ****************
+struct CGEscFinder : public CGVisitor{
+ CGFrame *frame;
+
+ CGEscFinder( CGFrame *f ):frame(f){}
+
+ CGExp *visit( CGExp *exp ){
+ if( CGLea *p=exp->lea() ){
+ CGTmp *t=p->exp->tmp();
+ if( !t ) return exp;
+ if( frame->tmps.find(t->ident)==frame->tmps.end() ){
+ frame->tmps.insert( make_pair(t->ident,frame->allocLocal(t->type)) );
+ }
+ }else if( CGTmp *t=exp->tmp() ){
+ //always spill bytes, shorts, longs...
+ if( t->type==CG_INT8 || t->type==CG_INT16 || t->type==CG_INT64 ){
+ if( frame->tmps.find(t->ident)==frame->tmps.end() ){
+ frame->tmps.insert( make_pair(t->ident,frame->allocLocal(t->type)) );
+ }
+ }
+ }
+ return exp;
+ }
+};
+
+void CGFrame::findEscapes(){
+
+ if( fun->type==CG_INT64 ) int64ret=reg(CG_PTR);
+
+ CGEscFinder vis( this );
+
+ fun=CG::visitFun( fun,vis );
+}
+
+//**************** Rename tmps ********************
+struct CGTmpRenamer : public CGVisitor{
+ CGFrame *frame;
+
+ CGTmpRenamer( CGFrame *f ):frame(f){}
+
+ CGExp *visit( CGExp *exp ){
+ if( CGTmp *t=exp->tmp() ){
+ return tmpReg( t );
+ }
+ return exp;
+ }
+
+ CGExp *tmpReg( CGTmp *t ){
+ IdExpMap::iterator it=frame->tmps.find(t->ident);
+
+ if( it==frame->tmps.end() ){
+
+ CGReg *owner=0;
+ if( t->owner ) owner=tmpReg( t->owner )->reg();
+
+ it=frame->tmps.insert( make_pair(t->ident,frame->reg(t->type,owner)) ).first;
+ }
+ return it->second;
+ }
+};
+
+void CGFrame::renameTmps(){
+
+ CGTmpRenamer vis( this );
+
+ fun=CG::visitFun( fun,vis );
+}
+
+//**************** PreOptimize ********************
+static int shifter( int n ){
+ int k;
+ for( k=0;k<32;++k ) if( n==(1<<k) ) return k;
+ return -1;
+}
+
+struct CGPreOpter : public CGVisitor{
+ CGFrame *frame;
+
+ CGPreOpter( CGFrame *f ):frame(f){}
+
+ CGStm *visit( CGStm *stm ){
+ if( CGBcc *t=stm->bcc() ){
+ if( CGScc *p=t->lhs->scc() ){
+ if( CGLit *q=t->rhs->lit() ){
+ if( !q->int_value ){
+ if( t->cc==CG_NE ){
+ //bcc NE,scc,0,sym
+ return CG::bcc( p->cc,p->lhs,p->rhs,t->sym );
+ }else if( t->cc==CG_EQ ){
+ //bcc EQ,scc,0,sym
+ return CG::bcc( CG::swapcc(p->cc),p->lhs,p->rhs,t->sym );
+ }
+ }
+ }
+ }
+ return stm;
+ }
+ return stm;
+ }
+
+
+ CGExp *visit( CGExp *exp ){
+
+ if( CGCvt *t=exp->cvt() ){
+ //remove cvt between same types
+ CGExp *e=t->exp;
+ if( t->type==e->type ) exp=e;
+ return exp;
+ }
+
+ if( CGMem *t=exp->mem() ){
+ //remove mem(lea(mem),0)...
+ CGExp *e=t->exp;
+ CGLea *p=e->lea();
+ assert( !p || p->exp->mem() );
+ if( p && !t->offset && t->type==p->exp->mem()->type ) exp=p->exp;
+ return exp;
+ }
+
+ if( CGUop *t=exp->uop() ){
+ //const precalc unary op
+ if( t->isfloat() ) return exp;
+ if( CGLit *p=t->exp->lit() ){
+ int n=p->int_value;
+ switch( t->op ){
+ case CG_NOT:exp=CG::lit(~n);break;
+ case CG_NEG:exp=CG::lit(-n);break;
+ }
+ }
+ return exp;
+ }
+
+ if( CGBop *t=exp->bop() ){
+ if( t->isfloat() ) return exp;
+
+ //const precalc binary op
+ CGLit *p=t->lhs->lit(),*q=t->rhs->lit();
+
+ if( p && !q && t->commutes() ){
+ //put const on RHS in commuting const,non-const BOPs.
+ std::swap(p,q);
+ exp=t=CG::bop(t->op,t->rhs,q);
+ }
+
+ if( p && q ){
+ //const,const
+ int x=p->int_value,y=q->int_value;
+ switch( t->op ){
+ case CG_ADD:exp=CG::lit(x+y);break;
+ case CG_SUB:exp=CG::lit(x-y);break;
+ case CG_MUL:exp=CG::lit(x*y);break;
+ case CG_DIV:assert(y);exp=CG::lit(x/y);break;
+ case CG_MOD:assert(y);exp=CG::lit(x%y);break;
+ case CG_AND:exp=CG::lit(x&y);break;
+ case CG_ORL:exp=CG::lit(x|y);break;
+ case CG_XOR:exp=CG::lit(x^y);break;
+ case CG_SHL:exp=CG::lit(x<<y);break;
+ case CG_SHR:exp=CG::lit((int)((unsigned)x>>(unsigned)y));break;
+ case CG_SAR:exp=CG::lit(x>>y);break;
+ }
+ }else if( p ){
+ //const,non-const (ie: non-commuting)
+ switch( p->int_value ){
+ case 0:
+ switch( t->op ){
+ case CG_DIV:case CG_MOD:
+ case CG_SHL:case CG_SHR:case CG_SAR:
+ exp=CG::lit0;break;
+ }
+ break;
+ }
+ }else if( q ){
+ //non-const,const
+ switch( q->int_value ){
+ case 0:
+ switch( t->op ){
+ case CG_ADD:case CG_SUB:
+ case CG_ORL:case CG_XOR:
+ case CG_SHL:case CG_SHR:case CG_SAR:
+ exp=t->lhs;break;
+ case CG_MUL:case CG_AND:
+ exp=CG::lit0;break;
+ }
+ break;
+ case 1:
+ switch( t->op ){
+ case CG_MUL:case CG_DIV:
+ exp=t->lhs;break;
+ }
+ break;
+ }
+ }
+ return exp;
+ }
+ return exp;
+ }
+};
+
+void CGFrame::preOptimize(){
+
+ CGPreOpter vis( this );
+
+ fun=CG::visitFun( fun,vis );
+}
+
+//****************** GenAssem *********************
+void CGFrame::genAssem(){
+ assem.clear();
+ asm_it=assem.end;
+ genFun();
+}
+
+//**************** Create flow ********************
+void CGFrame::createFlow(){
+ deleteFlow();
+ flow=new CGFlow(assem);
+ flow->liveness();
+}
+
+//**************** Create a reg *******************
+CGReg *CGFrame::reg( int type,CGReg *owner,int color ){
+ assert( type!=CG_INT64 );
+ CGReg *r=new CGReg;
+ r->type=type;
+ r->id=regs.size();
+ r->owner=owner;
+ r->color=color;
+ regs.push_back(r);
+ return r;
+}
+
+//*************** Generate assem ******************
+static CGIntSet *genUse;
+
+CGAsm *CGFrame::gen( CGStm *stm,const char *fmt,... ){
+ CGAsm *as;
+ if( fmt ){
+ char buf[256];
+ buf[255]=0;
+
+ va_list args;
+ va_start( args,fmt );
+ vsprintf( buf,fmt,args );
+ assert( !buf[255] );
+
+ as=new CGAsm( stm,buf );
+
+ }else{
+ as=new CGAsm( stm,"" );
+ }
+
+ if( genUse ) as->use.insert( *genUse );
+
+ asm_it=assem.insert(as,asm_it)->succ;
+ return as;
+}
+
+//*************** Elim dead code ******************
+void CGFrame::optDeadCode(){
+ for(;;){
+ bool changed=false;
+ CGBlockIter blk_it;
+ for( blk_it=flow->blocks.begin();blk_it!=flow->blocks.end();++blk_it ){
+ CGBlock *blk=*blk_it;
+
+ CGAsm *as=blk->end;
+
+ CGIntSet live=blk->live_out;
+
+ while( as!=blk->begin ){
+ as=as->pred;
+
+ bool elim=false;
+
+ CGMov *t=as->stm->mov();
+
+ if( t ){
+ CGReg *lhs=t->lhs->reg();
+ CGReg *rhs=t->rhs->reg();
+ if( lhs && rhs && lhs==rhs ){
+ elim=true;
+ }else if( lhs && !t->rhs->sideEffects() && !live.count(lhs->id) ){
+ elim=true;
+ }
+ }
+
+ if( elim ){
+ as=assem.erase(as);
+ changed=true;
+ }else{
+ live.erase( as->def );
+ live.insert( as->use );
+ }
+ }
+ }
+ if( !changed ) break;
+ flow->liveness();
+ }
+}
+
+//*************** Optimize loads ******************
+/*
+This is dodgy and probably not worth it...
+CGMov to reg should eliminate any loads which depend on reg - this doesn't.
+*/
+void CGFrame::optDupLoads(){
+ /*
+ vector<CGMov*> loads;
+
+ bool changed=false;
+
+ for( asm_it=assem.begin;asm_it!=assem.end;asm_it=asm_it->succ ){
+
+ CGMov *t=asm_it->stm->mov();
+ if( !t || t->lhs->mem() || t->rhs->sideEffects() ){
+ loads.clear();
+ continue;
+ }
+
+ if( !t->rhs->mem() ){
+ continue;
+ }
+
+ int k;
+ for( k=0;k<loads.size();++k ){
+ if( !t->rhs->equals(loads[k]->rhs) ) continue;
+ //found a load!
+ cout<<"Eliminating load!"<<endl;
+ asm_it=assem.erase(asm_it);
+ genStm( CG::mov(t->lhs,loads[k]->lhs) );
+ asm_it=asm_it->pred;
+ changed=true;
+ break;
+ }
+ if( k==loads.size() ) loads.push_back( t );
+ }
+ if( changed ) flow->liveness();
+ */
+}
+
+//*************** Allocate regs *******************
+struct Spiller : public CGVisitor{
+
+ CGReg *reg;
+ CGExp *exp;
+ CGIntSet owners;
+
+ Spiller( CGReg *r,CGExp *e ):reg(r),exp(e){}
+
+ CGExp *visit( CGExp *e ){
+ CGReg *t=e->reg();
+ if( t!=reg ) return e;
+
+ while( t=t->owner ){
+ owners.insert( t->id );
+ }
+
+ return exp;
+ /*
+ if( t==reg ) return exp;
+ CGReg *r=reg;
+ while( r=r->owner ){
+ if( r==t ) owned.insert( r->id );
+ }
+ return e;
+ */
+ }
+};
+
+void CGFrame::spillReg( CGReg *reg,CGExp *exp ){
+
+ if( !exp ) exp=allocSpill(reg);
+
+ int i;
+ for( i=0;i<regs.size();++i ){
+ if( regs[i]->owner==reg ) regs[i]->owner=0;
+ }
+
+ Spiller spiller( reg,exp );
+
+ asm_it=assem.begin;
+ while( asm_it!=assem.end ){
+ spiller.owners.clear();
+ CGStm *stm=asm_it->stm->visit( spiller );
+ if( stm==asm_it->stm ){
+ asm_it->use.erase( reg->id );
+ asm_it=asm_it->succ;
+ continue;
+ }
+ asm_it=assem.erase( asm_it );
+ genUse=&spiller.owners;
+ genStm( stm );
+ genUse=0;
+ /*
+ asm_it=assem.erase( asm_it );
+ genStm( stm );
+ asm_it->pred->use.insert( spiller.owned );
+ */
+ }
+}
+
+void CGFrame::allocRegs(){
+
+ cgAllocRegs( this );
+
+ CGAsm *as=assem.begin;
+
+ while( as!=assem.end ){
+
+ if( CGMov *t=as->stm->mov() ){
+ CGReg *lhs=t->lhs->reg(),*rhs=t->rhs->reg();
+ if( lhs && rhs && lhs->color==rhs->color ){
+ as=assem.erase(as);
+ continue;
+ }
+ }
+
+ char buf[256],*q=buf;
+ const char *p=as->assem;
+
+ while( const char *t=strchr(p,'\'') ){
+
+ memcpy(q,p,t-p);
+ q+=t-p;
+
+ int n=0,c;
+ while( isdigit(c=*++t) ) n=n*10+(c-'0');
+
+ CGReg *r=regs[n];
+
+ int bank=reg_banks[r->type];
+ const char *name=reg_names[bank][r->color];
+
+ strcpy( q,name );
+ q+=strlen(q);
+
+ p=t;
+ }
+
+ if( q!=buf ){
+ strcpy(q,p);
+ as->assem=strdup(buf);
+ }
+
+ as=as->succ;
+ }
+}
+
+void CGFrame::deleteFlow(){
+ if( flow ){
+ delete flow;
+ flow=0;
+ }
+}
+
+void CGFrame::peepOpt(){
+ CGAsm *as;
+ for( as=assem.begin;as!=assem.end;as=as->succ ){
+ if( CGBra *p=as->stm->bra() ){
+ if( CGLab *q=as->succ->stm->lab() ){
+ if( p->sym->value==q->sym->value ){
+ cout<<"Erasing:"<<as->assem<<endl;
+ as=assem.erase( as );
+ continue;
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+
+#ifndef CGFRAME_H
+#define CGFRAME_H
+
+#include "cgflow.h"
+
+struct CGFrame{
+ CGFun* fun;
+ CGFlow* flow;
+ CGAsmSeq assem;
+ CGAsm* asm_it;
+ CGReg* int64ret;
+ bool big_endian,little_endian;
+
+ int reg_banks[8]; //maps types->banks
+ int reg_masks[4]; //usable regs per bank
+ vector<const char*> reg_names[4]; //reg names per bank
+
+ vector<CGReg*> regs;
+ map<string,CGExp*> tmps;
+
+ CGFrame( CGFun *fun );
+ virtual ~CGFrame();
+
+ //before ASM is generated
+ void findEscapes(); //local escaping tmps
+ void renameTmps(); //rename tmps->regs
+ void fixInt64();
+ void linearize(); //remove SEQ and ESQ nodes
+ void fixSymbols(); //fix symbols depending on platform
+ void preOptimize(); //do some opts before asm gen
+
+ //generate ASM
+ void genAssem(); //create assem from fun
+ void createFlow(); //create flowgraph
+
+ //optimize FlowGraph
+ void optDeadCode(); //eliminate dead code
+ void optDupLoads(); //eliminate extra 'loads'
+
+ //assign regs/rewrite src
+ void allocRegs(); //alloc registers
+ void spillReg( CGReg *r,CGExp *e );
+
+ void deleteFlow();
+ void peepOpt();
+
+ CGMem* int64el( CGMem *i64,int n );
+ CGMem* int64lo( CGMem *i64 );
+ CGMem* int64hi( CGMem *i64 );
+
+ CGReg* reg( int type,CGReg *owner=0,int color=-1 );
+ CGAsm* gen( CGStm *stm,const char *fmt,... );
+
+ virtual string fixSym( string id )=0;
+ virtual void genFun()=0;
+ virtual void genStm( CGStm *stm )=0;
+ virtual CGMem* allocLocal( int type )=0;
+ virtual CGExp* allocSpill( CGReg *r )=0;
+ virtual void finish()=0;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgframe_ppc.h"
+#include "cgmodule_ppc.h"
+
+#include "cgutil.h"
+#include "cgdebug.h"
+
+using namespace CG;
+
+enum{
+ MEM_PARAM=1,
+ MEM_LOCAL=2
+};
+
+CGMem *CGFrame_PPC::genMem( CGMem *m,char *buf ){
+ CGReg *r=genExp(m->exp);
+ const char *q="";
+ switch( m->flags ){
+ case MEM_PARAM:q="__FRAME+";break;
+ case MEM_LOCAL:q="__LOCAL+";break;
+ }
+ sprintf( buf,"%s%i('%i)",q,m->offset,r->id );
+ CGMem *t=mem(m->type,r,m->offset);
+ t->flags=m->flags;
+ return t;
+}
+
+CGReg *CGFrame_PPC::genLoad( CGMem *m ){
+
+ CGReg *r=reg(m->type);
+
+ const char *op=0;
+ switch( m->type ){
+ case CG_INT8:op="lbz";break;
+ case CG_INT16:op="lhz";break;
+ case CG_FLOAT32:op="lfs";break;
+ case CG_FLOAT64:op="lfd";break;
+ default:op="lwz";
+ }
+ char buf[256];
+ m=genMem(m,buf);
+ gen( mov(r,m),
+ "\t%s\t'%i,%s\n",op,r->id,buf );
+ return r;
+}
+
+void CGFrame_PPC::genStore( CGMem *m,CGExp *e ){
+
+ CGReg *r=genExp(e);
+
+ const char *op=0;
+ switch( m->type ){
+ case CG_INT8:op="stb";break;
+ case CG_INT16:op="sth";break;
+ case CG_FLOAT32:op="stfs";break;
+ case CG_FLOAT64:op="stfd";break;
+ default:op="stw";
+ }
+ char buf[256];
+ m=genMem(m,buf);
+ gen( mov( m,r ),"\t%s\t'%i,%s\n",op,r->id,buf );
+}
+
+void CGFrame_PPC::genCopy( CGReg *d,CGReg *r ){
+ const char *op=d->isint() ? "mr" : "fmr";
+ gen( mov(d,r),"\t%s\t'%i,'%i\n",op,d->id,r->id );
+}
+
+void CGFrame_PPC::genMov( CGExp *lhs,CGExp *rhs ){
+ if( lhs->equals(rhs) ) return;
+ if( CGMem *t=lhs->mem() ){
+ genStore( t,rhs );
+ }else if( CGReg *t=lhs->reg() ){
+ genCopy( t,genExp( rhs ) );
+ }else{
+ assert(0);
+ }
+}
+
+CGReg *CGFrame_PPC::genExp( CGExp *e ){
+ if( CGReg *t=e->reg() ){
+ return t;
+ }else if( CGMem *t=e->mem() ){
+ return genLoad( t );
+ }else if( CGLea *t=e->lea() ){
+ return genLea( t );
+ }else if( CGCvt *t=e->cvt() ){
+ return genCvt( t );
+ }else if( CGUop *t=e->uop() ){
+ return genUop( t );
+ }else if( CGBop *t=e->bop() ){
+ return genBop( t );
+ }else if( CGScc *t=e->scc() ){
+ return genScc( t );
+ }else if( CGJsr *t=e->jsr() ){
+ return genJsr( t );
+ }else if( CGLit *t=e->lit() ){
+ return genLit( t );
+ }else if( CGSym *t=e->sym() ){
+ return genSym( t );
+ }else if( CGFrm *t=e->frm() ){
+ return genFrm( t );
+ }
+ cout<<e<<endl;
+ assert(0);
+ return 0;
+}
+
+CGExp *CGFrame_PPC::genExp( CGExp *e,char *buf,int &mask ){
+ if( mask & (EA_SIMM|EA_UIMM) ){
+ if( CGLit *t=e->lit() ){
+ if( t->isint() ){
+ int n=t->int_value;
+ if( (mask & EA_SIMM) && n>=-32768 && n<32768 ){
+ sprintf( buf,"%i",n );
+ mask=EA_SIMM;
+ return e;
+ }
+ if( (mask & EA_UIMM) && n>=0 && n<65536 ){
+ sprintf( buf,"%i",n );
+ mask=EA_UIMM;
+ return e;
+ }
+ }
+ }
+ }
+ CGReg *r=genExp( e );
+ sprintf( buf,"'%i",r->id );
+ mask=0;
+ return r;
+}
+
+CGReg *CGFrame_PPC::genLea( CGLea *e ){
+
+ CGReg *r=reg(e->type);
+ CGMem *m=e->exp->mem();
+
+ assert( m );
+
+ char buf[256];
+ m=genMem(m,buf);
+ gen( mov(r,lea(m)),"\tla\t'%i,%s\n",r->id,buf );
+ return r;
+}
+
+CGReg *CGFrame_PPC::genCvt( CGCvt *e ){
+
+ CGReg *r=reg(e->type);
+
+ if( r->isint() && e->exp->isint() ){
+ //int to int
+ CGReg *t=genExp(e->exp);
+ if( r->type==CG_INT8 && e->exp->type!=CG_INT8 ){
+ gen( mov(r,cvt(r->type,t)),
+ "\tandi.\t'%i,'%i,0xff\n",
+ r->id,t->id );
+ }else if( r->type==CG_INT16 && e->exp->type==CG_INT32 ){
+ gen( mov(r,cvt(r->type,t)),
+ "\tandi.\t'%i,'%i,0xffff\n",
+ r->id,t->id );
+ }else{
+ gen( mov(r,cvt(r->type,t)),
+ "\tmr\t'%i,'%i\n",
+ r->id,t->id );
+ }
+ }else if( r->isfloat() && e->exp->isfloat() ){
+ //float to float
+ CGReg *t=genExp(e->exp);
+ gen( mov(r,cvt(r->type,t)),
+ "\tfmr\t'%i,'%i\n",
+ r->id,t->id );
+ }else if( r->isint() && e->exp->isfloat() ){
+ //float to int
+ if( tmp_disp8<0 ){
+ tmp_disp8=local_sz;
+ local_sz+=8;
+ }
+ int off;
+ const char *op;
+ switch( r->type ){
+ case CG_INT8:off=7;op="lbz";break;
+ case CG_INT16:off=6;op="lhz";break;
+ case CG_INT32:case CG_PTR:off=4;op="lwz";break;
+ default:assert(0);
+ }
+ CGReg *t=genExp(e->exp),*f=F[0];
+
+ CGAsm *as=gen( mov(r,cvt(e->type,t)),
+ "\tfctiwz\t'%i,'%i\n"
+ "\tstfd\t'%i,__LOCAL+%i(r1)\n"
+ "\t%s\t'%i,__LOCAL+%i+%i(r1)\n",
+ f->id,t->id,
+ f->id,tmp_disp8,
+ op,r->id,tmp_disp8,off );
+ as->def.insert(f->id);
+
+ }else if( r->isfloat() && e->exp->isint() ){
+ //int to float
+ if( tmp_disp8<0 ){
+ tmp_disp8=local_sz;
+ local_sz+=8;
+ }
+ if( !mod_ppc->fp_const ){
+ mod_ppc->fp_const=sym();
+ }
+ CGReg *t=reg(CG_INT32),*f=F[0];
+
+ string p=mod_ppc->fp_const->value;
+
+ genMov( t,genExp(e->exp) );
+
+ CGAsm *as=gen( mov(r,cvt(e->type,t)),
+ "\tlis\tr0,0x4330\n"
+ "\tstw\tr0,__LOCAL+%i(r1)\n"
+ "\txoris\t'%i,'%i,0x8000\n"
+ "\tstw\t'%i,__LOCAL+%i+4(r1)\n"
+ "\tlis\t'%i,ha16(%s)\n"
+ "\tlfd\t'%i,lo16(%s)('%i)\n"
+ "\tlfd\t'%i,__LOCAL+%i(r1)\n"
+ "\tfsub\t'%i,'%i,'%i\n",
+ tmp_disp8,
+ t->id,t->id,
+ t->id,tmp_disp8,
+ t->id,p.c_str(),
+ f->id,p.c_str(),t->id,
+ r->id,tmp_disp8,
+ r->id,r->id,f->id );
+ as->use.insert(t->id);
+ as->def.insert(t->id);
+ as->def.insert(f->id);
+
+ }else{
+ assert(0);
+ }
+
+ return r;
+
+ /* int r3 to float f1
+ addis R0,R0,0x4330 # R0 = 0x43300000
+ stw R0,disp(R1) # store upper half
+ xoris R3,R3,0x8000 # flip sign bit
+ stw R3,disp+4(R1) # store lower half
+ lfd FR1,disp(R1) # float load double of value
+ fsub FR1,FR1,FR2 # subtract 0x4330000080000000
+ */
+
+ /* float f1 to int r3
+ fctiw[z] FR2,FR1 # convert to integer
+ stfd FR2,disp(R1) # copy unmodified to memory
+ lwz R3,disp+4(R1) # load the low-order 32 bits
+ */
+}
+
+CGReg *CGFrame_PPC::genUop( CGUop *e ){
+
+ const char *op=0;
+
+ switch( e->op ){
+ case CG_NOT:assert(e->isint());op="not";break;
+ case CG_NEG:op=e->isfloat() ? "fneg" : "neg";break;
+ default:assert(0);
+ }
+
+ CGReg *r=reg(e->type);
+ CGReg *s=genExp(e->exp);
+ gen( mov(r,uop(e->op,s)),"\t%s\t'%i,'%i\n",op,r->id,s->id );
+ return r;
+}
+
+static int shifter( int n ){
+ int k;
+ for( k=0;k<32;++k ) if( (1<<k)==n ) return k;
+ return -1;
+}
+
+CGReg *CGFrame_PPC::genBop( CGBop *e ){
+
+ if( e->isint() && (e->op==CG_MUL || e->op==CG_DIV) ){
+ if( CGLit *c=e->rhs->lit() ){
+ int i=c->int_value;
+ if( e->op==CG_MUL ){
+ int n=shifter(i);
+ if( n!=-1 ){
+ CGReg *r=reg(e->type);
+ CGReg *t=genExp(e->lhs);
+ gen( mov(r,bop(e->op,t,c)),
+ "\tslwi\t'%i,'%i,%i\n",
+ r->id,t->id,n );
+ return r;
+ }
+ }else if( e->op==CG_DIV ){
+ int n=shifter(i);
+ if( n!=-1 ){
+ CGReg *r=reg(e->type);
+ CGReg *t=genExp(e->lhs);
+ gen( mov(r,bop(e->op,t,c)),
+ "\tsrawi\t'%i,'%i,%i\n"
+ "\taddze\t'%i,'%i\n",
+ r->id,t->id,n,r->id,r->id );
+ return r;
+ }
+ }
+ }
+ }
+
+ CGReg *r=reg(e->type);
+
+ const char *op=0;
+
+ int mask=0;
+
+ if( e->isfloat() ){
+ switch( e->op ){
+ case CG_ADD:op="fadd";break;
+ case CG_SUB:op="fsub";break;
+ case CG_MUL:op="fmul";break;
+ case CG_DIV:op="fdiv";break;
+ }
+ }else{
+ switch( e->op ){
+ case CG_ADD:op="add";mask=EA_SIMM;break;
+ case CG_SUB:op="sub";mask=EA_SIMM;break;
+ case CG_MUL:op="mullw";mask=EA_SIMM;break;
+ case CG_DIV:op="divw";break;
+ case CG_AND:op="and";mask=EA_UIMM;break;
+ case CG_ORL:op="or";mask=EA_UIMM;break;
+ case CG_XOR:op="xor";mask=EA_UIMM;break;
+ case CG_SHL:op="slw";break;
+ case CG_SHR:op="srw";break;
+ case CG_SAR:op="sraw";break;
+ }
+ }
+
+ if( op ){
+
+ char buf[256];
+ CGReg *lhs=genExp(e->lhs);
+ CGExp *rhs=genExp(e->rhs,buf,mask);
+ const char *ext="";
+ if( mask ){
+ ext="i";
+ switch( e->op ){
+ case CG_AND:ext="i.";break;
+ case CG_MUL:op="mull";break;
+ }
+ }
+
+ gen( mov(r,bop(e->op,lhs,rhs)),
+ "\t%s%s\t'%i,'%i,%s\n",op,ext,r->id,lhs->id,buf );
+
+ return r;
+ }
+
+ if( e->op==CG_MOD && e->isint() ){
+ CGReg *lhs=genExp(e->lhs);
+ CGReg *rhs=genExp(e->rhs);
+ //divw Rt,Ra,Rb # quotient = (int)(Ra / Rb)
+ //mullw Rt,Rt,Rb # quotient * Rb
+ //subf Rt,Rt,Ra # remainder = Ra - quotient * Rb
+ gen( mov(r,bop(e->op,lhs,rhs)),
+ "\tdivw\tr0,'%i,'%i\n"
+ "\tmullw\tr0,r0,'%i\n"
+ "\tsubf\t'%i,r0,'%i\n",
+ lhs->id,rhs->id,rhs->id,r->id,lhs->id );
+ return r;
+ }
+ assert(0);
+ return 0;
+}
+
+CGReg *CGFrame_PPC::genScc( CGScc *e ){
+
+ CGReg *r=reg(CG_INT32);
+
+ CGReg *lhs=genExp(e->lhs);
+ CGReg *rhs=genExp(e->rhs);
+
+ int bit=0;
+ char cror[256];cror[0]=0;
+ char exor[256];exor[0]=0;
+
+ const char *op=lhs->isfloat() ? "fcmpu" : "cmpw";
+
+ switch( e->cc ){
+ case CG_LT:bit=29;break;
+ case CG_GT:bit=30;break;
+ case CG_EQ:bit=31;break;
+ case CG_LE:bit=0;sprintf(cror,"\tcror\t31,30,28\n");break;
+ case CG_GE:bit=0;sprintf(cror,"\tcror\t31,30,29\n");break;
+ case CG_NE:bit=31;sprintf(exor,"\txori\t'%i,'%i,1\n",r->id,r->id);break;
+ case CG_LTU:bit=29;op="cmplw";break;
+
+ default:assert(0);
+ }
+
+ gen( mov(r,scc(e->cc,lhs,rhs)),
+ "\t%s\tcr7,'%i,'%i\n%s"
+ "\tmfcr\t'%i\n"
+ "\trlwinm\t'%i,'%i,%i,31,31\n%s",
+ op,lhs->id,rhs->id,cror,r->id,r->id,r->id,bit,exor );
+
+ return r;
+}
+
+CGReg *CGFrame_PPC::genJsr( CGJsr *e ){
+
+ vector<CGExp*> args;
+
+ int k;
+ for( k=e->args.size()-1;k>=0;--k ){
+ CGExp *arg=e->args[k];
+ args.push_back( genExp(e->args[k]) );
+ }
+ CGExp *ea=e->exp;
+ if( CGVfn *t=ea->vfn() ){
+ args.push_back( genExp(t->self) );
+ ea=t->exp;
+ }
+ ea=genExp(ea);
+
+ int arg_sz=0,fp_id=1;
+ for( k=args.size()-1;k>=0;--k ){
+ CGExp *t=args[k],*p;
+ if( t->isfloat() && fp_id<14 ){
+ p=F[fp_id++];
+ }else if( t->isfloat() || arg_sz>=32 ){
+ p=mem(t->type,R[1],arg_sz+24 );
+ }else{
+ p=R[arg_sz/4+3];
+ }
+ arg_sz+=(t->type==CG_FLOAT64) ? 8 : 4;
+ genMov( p,t );
+ args[k]=p;
+ }
+ if( arg_sz>param_sz ) param_sz=arg_sz;
+
+ CGExp *dst=e->isfloat() ? F[1] : R[3];
+
+ CGAsm *as=gen( mov(dst,jsr(e->type,e->call_conv,ea,args)),
+ "\tmtctr\t'%i\n"
+ "\tbctrl\n",ea->reg()->id );
+
+ for( k=3;k<13;++k ) as->def.insert( R[k]->id );
+ for( k=1;k<14;++k ) as->def.insert( F[k]->id );
+
+ CGReg *r=reg( e->type );
+ genMov( r,dst );
+ return r;
+}
+
+CGReg *CGFrame_PPC::genLit( CGLit *e ){
+
+ CGReg *r=reg(e->type);
+
+ if( e->isfloat() ){
+ CGDat *d=dat();
+ d->push_back(e);
+ genMov( r,mem(e->type,d,0) );
+ return r;
+ }
+ CGStm *m=mov(r,e);
+ int n=e->int_value;
+ if( n>=-32768 && n<32768 ){
+ //16 bit signed
+ gen( m,
+ "\tli\t'%i,%i\n",r->id,n );
+ }else if( !(n&65535) ){
+ //32 bit - 0 low word
+ gen( m,
+ "\tlis\t'%i,%i\n",r->id,(n>>16) );
+ }else{
+ //32 bit
+ gen( m,
+ "\tlis\t'%i,%i\n"
+ "\tori\t'%i,'%i,%i\n",r->id,(n>>16),r->id,r->id,(n&65535) );
+ }
+ return r;
+}
+
+CGReg *CGFrame_PPC::genSym( CGSym *e ){
+ CGReg *r=reg(e->type);
+ if( e->linkage==CG_IMPORT ){
+ string t=""+e->value+"$non_lazy_ptr";
+ gen( mov(r,e),
+ "\tlis\t'%i,ha16(%s)\n"
+ "\tlwz\t'%i,lo16(%s)('%i)\n",r->id,t.c_str(),r->id,t.c_str(),r->id );
+ }else{
+ gen( mov(r,e),
+ "\tlis\t'%i,hi16(%s)\n"
+ "\tori\t'%i,'%i,lo16(%s)\n",r->id,e->value.c_str(),r->id,r->id,e->value.c_str() );
+ }
+ return r;
+}
+
+CGReg *CGFrame_PPC::genFrm( CGFrm *e ){
+ CGReg *r=reg(CG_PTR);
+ gen( mov(r,e),
+ "\tla\t'%i,__LOCAL(r1)\n",r->id );
+ return r;
+}
+
+void CGFrame_PPC::genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ){
+
+ if( cc==CG_LTU ){
+ genBcc( CG_NE,scc(cc,lhs,rhs),lit0,sym );
+ return;
+ }
+
+ int tcc=cc;
+ if( bigFun ) cc=CG::swapcc(cc);
+
+ const char *p;
+ switch( cc ){
+ case CG_LT:p="lt";break;
+ case CG_GT:p="gt";break;
+ case CG_EQ:p="eq";break;
+ case CG_LE:p="le";break;
+ case CG_GE:p="ge";break;
+ case CG_NE:p="ne";break;
+ default:assert(0);
+ }
+
+ if( lhs->isfloat() ){
+ CGReg *x=genExp(lhs);
+ CGReg *y=genExp(rhs);
+ if( bigFun ){
+ CGSym *t=CG::sym();
+ gen( bcc(tcc,x,y,sym),
+ "\tfcmpu\tcr0,'%i,'%i\n"
+ "\tb%s\t%s\n\tb\t%s\n%s:\n",x->id,y->id,p,t->value.c_str(),sym->value.c_str(),t->value.c_str() );
+ }else{
+ gen( bcc(cc,x,y,sym),
+ "\tfcmpu\tcr0,'%i,'%i\n"
+ "\tb%s\t%s\n",x->id,y->id,p,sym->value.c_str() );
+ }
+ return;
+ }
+
+ char buf[256];
+ int mask=EA_SIMM;
+ CGReg *x=genExp(lhs);
+ CGExp *y=genExp(rhs,buf,mask);
+ const char *ext=mask ? "i" : "";
+ if( bigFun ){
+ CGSym *t=CG::sym();
+ gen( bcc(tcc,x,y,sym),
+ "\tcmpw%s\t'%i,%s\n"
+ "\tb%s\t%s\n\tb\t%s\n%s:\n",ext,x->id,buf,p,t->value.c_str(),sym->value.c_str(),t->value.c_str() );
+ }else{
+ gen( bcc(cc,x,y,sym),
+ "\tcmpw%s\t'%i,%s\n"
+ "\tb%s\t%s\n",ext,x->id,buf,p,sym->value.c_str() );
+ }
+}
+
+void CGFrame_PPC::genRet( CGExp *e ){
+ CGReg *r=0;
+ if( e ){
+ r=e->isfloat() ? F[1] : R[3];
+ genMov(r,e);
+ }
+ CGAsm *as=gen( ret(r),"\tblr\n" );
+ as->use.insert( R[1]->id );
+}
+
+string CGFrame_PPC::fixSym( string id ){
+ return "_"+id;
+}
+
+void CGFrame_PPC::genStm( CGStm *s ){
+
+ if( CGAti *t=s->ati() ){
+ char buf[256];
+ CGMem *m=genMem( t->mem,buf );
+ CGAsm *as=gen( ati(m),
+ "\tlwz\tr2,%s\n"
+ "\taddi\tr2,r2,1\n"
+ "\tstw\tr2,%s\n",
+ buf,buf );
+ /*
+ CGReg *r=genLea( lea(t->mem) );
+ CGAsm *as=gen( ati(mem(CG_INT32,r,0)),
+ "1:\n"
+ "\tlwarx\tr2,0,'%i\n"
+ "\taddi\tr2,r2,1\n"
+ "\tstwcx.\tr2,0,'%i\n"
+ "\tbne\t1b\n",
+ r->id,r->id );
+ */
+ }else if( CGAtd *t=s->atd() ){
+ char buf[256];
+ CGMem *m=genMem( t->mem,buf );
+ CGAsm *as=gen( atd(m,t->sym),
+ "\tlwz\tr2,%s\n"
+ "\taddi\tr2,r2,-1\n"
+ "\tstw\tr2,%s\n"
+ "\tcmpwi\tr2,0\n"
+ "\tbne\t%s\n",
+ buf,buf,t->sym->value.c_str() );
+ /*
+ CGReg *r=genLea( lea(t->mem) );
+ CGAsm *as=gen( atd(mem(CG_INT32,r,0),t->sym),
+ "1:\n"
+ "\tlwarx\tr2,0,'%i\n"
+ "\taddi\tr2,r2,-1\n"
+ "\tstwcx.\tr2,0,'%i\n"
+ "\tbne\t1b\n"
+ "\tor.\tr2,r2,r2\n"
+ "\tbne\t%s\n",
+ r->id,r->id,t->sym->value.c_str() );
+ */
+ }else if( CGMov *t=s->mov() ){
+ genMov( t->lhs,t->rhs );
+ }else if( CGLab *t=s->lab() ){
+ gen( t,"%s:\n",t->sym->value.c_str() );
+ }else if( CGBra *t=s->bra() ){
+ gen( t,"\tb\t%s\n",t->sym->value.c_str() );
+ }else if( CGBcc *t=s->bcc() ){
+ genBcc( t->cc,t->lhs,t->rhs,t->sym );
+ }else if( CGEva *t=s->eva() ){
+ if( t->exp->dat() ){
+ gen( t,"" );
+ }else{
+ genExp( t->exp );
+ }
+ }else if( CGRem *t=s->rem() ){
+ gen( t,"\t;%s\n",t->comment.c_str() );
+ }else if( CGRet *t=s->ret() ){
+ genRet( t->exp );
+ }else if( CGXop *t=s->xop() ){
+ assert(0);
+ }else{
+ assert(0);
+ }
+}
+
+void CGFrame_PPC::genFun(){
+
+ param_sz=32;
+ tmp_disp8=-1;
+
+ int k,arg_sz=0,fp_id=1;
+
+ //move self to tmp
+ if( CGExp *t=fun->self ){
+ //get 'this' from stack
+ genMov( t,R[3] );
+ arg_sz+=4;
+ }
+
+ //move args to tmps
+ for( k=0;k<fun->args.size();++k ){
+ CGExp *t=fun->args[k],*p;
+ if( t->isfloat() && fp_id<14 ){
+ p=F[fp_id++];
+ }else if( t->isfloat() || arg_sz>=32 ){
+ CGMem *m=mem(t->type,R[1],arg_sz+24 );
+ m->flags=MEM_PARAM;
+ p=m;
+ }else{
+ p=R[arg_sz/4+3];
+ }
+ arg_sz+=(t->type==CG_FLOAT64) ? 8 : 4;
+ genMov( t,p );
+ }
+
+ //genAsm for statements
+ for( k=0;k<fun->stms.size();++k ){
+ genStm( fun->stms[k] );
+ }
+}
+
+CGMem *CGFrame_PPC::allocLocal( int type ){
+ CGMem *m=mem(type,R[1],local_sz);
+ m->flags=MEM_LOCAL;
+ int sz=(type==CG_INT64 || type==CG_FLOAT64) ? 8 : 4;
+ local_sz+=sz;
+ return m;
+}
+
+CGExp *CGFrame_PPC::allocSpill( CGReg *r ){
+ return allocLocal( r->type );
+}
+
+void CGFrame_PPC::finish(){
+}
+
+CGFrame_PPC::CGFrame_PPC( CGFun *fun,CGModule_PPC *mod ):CGFrame(fun),
+mod_ppc(mod),local_sz(0){
+
+ bigFun=fun->stms.size()>300;
+/*
+ if( bigFun ){
+ printf( "Big function:%i stms\n",fun->stms.size() );
+ fflush( stdout );
+ }else{
+ printf( "Small function:%i stms\n",fun->stms.size() );
+ fflush( stdout );
+ }
+*/
+
+ //int types map to reg bank 0
+ reg_banks[CG_INT8]=0;
+ reg_banks[CG_INT16]=0;
+ reg_banks[CG_INT32]=0;
+ reg_banks[CG_PTR]=0;
+
+ //float types map to bank 1
+ reg_banks[CG_FLOAT32]=1;
+ reg_banks[CG_FLOAT64]=1;
+
+ //available reg masks
+ reg_masks[0]=0xfffffff8; //R0/R1/R2 unavailable!
+ reg_masks[1]=0xfffffffe; //F0 unavailable!
+
+ char *buf;
+
+ for( int k=0;k<32;++k ){
+
+ R[k]=reg( CG_INT32,0,k );
+ F[k]=reg( CG_FLOAT64,0,k );
+
+ buf=new char[4];
+ sprintf( buf,"r%i",k<13 ? k : 31+13-k );
+ reg_names[0].push_back( buf );
+
+ buf=new char[4];
+ sprintf( buf,"f%i",k );
+ reg_names[1].push_back( buf );
+ }
+}
--- /dev/null
+
+#ifndef CGFRAME_PPC_H
+#define CGFRAME_PPC_H
+
+#include "cgframe.h"
+
+struct CGModule_PPC;
+
+struct CGFrame_PPC : public CGFrame{
+
+ CGModule_PPC *mod_ppc;
+
+ int param_sz,local_sz,tmp_disp8,bigFun;
+
+ CGReg* R[32];
+ CGReg* F[32];
+
+ enum{
+ EA_SIMM=1,
+ EA_UIMM=2,
+ EA_SHIFTED=4
+ };
+ enum{
+ XOP_LWARX,
+ XOP_STWCX
+ };
+
+ CGMem* genMem( CGMem *exp,char *buf );
+
+ CGReg* genExp( CGExp *exp );
+ CGReg* genLea( CGLea *exp );
+ CGReg* genCvt( CGCvt *exp );
+ CGReg* genUop( CGUop *exp );
+ CGReg* genBop( CGBop *exp );
+ CGReg* genScc( CGScc *exp );
+ CGReg* genJsr( CGJsr *exp );
+ CGReg* genLit( CGLit *exp );
+ CGReg* genSym( CGSym *exp );
+ CGReg* genFrm( CGFrm *exp );
+
+ CGExp* genExp( CGExp *exp,char *buf,int &ea_mask );
+
+ CGReg* genLoad( CGMem *mem );
+ void genStore( CGMem *mem,CGExp *exp );
+ void genCopy( CGReg *dst,CGReg *src );
+ void genMov( CGExp *lhs,CGExp *rhs );
+ void genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym );
+ void genRet( CGExp *exp );
+
+ CGFrame_PPC( CGFun *fun,CGModule_PPC *mod );
+
+ virtual string fixSym( string id );
+ virtual void genFun();
+ virtual void genStm( CGStm *stm );
+ virtual CGMem* allocLocal( int type );
+ virtual CGExp* allocSpill( CGReg *r );
+ virtual void finish();
+};
+
+#endif
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgutil.h"
+#include "cgframe_x86.h"
+#include "cgmodule_x86.h"
+#include "cgdebug.h"
+
+using namespace CG;
+
+//Can't use %lld 'coz it doesn't work on mingw!
+//#define FMTI64 "%lld"
+
+const char *CGFrame_X86::x86cc( int cc ){
+ switch( cc ){
+ case CG_EQ:return "e";
+ case CG_NE:return "ne";
+ case CG_LT:return "l";
+ case CG_GT:return "g";
+ case CG_LE:return "le";
+ case CG_GE:return "ge";
+ case CG_LTU:return "b";
+ case CG_GTU:return "a";
+ case CG_LEU:return "be";
+ case CG_GEU:return "ae";
+ }
+ assert(0);
+ return 0;
+}
+
+const char *CGFrame_X86::x86size( int type ){
+ switch(type){
+ case CG_PTR:return "dword";
+ case CG_INT8:return "byte";
+ case CG_INT16:return "word";
+ case CG_INT32:return "dword";
+ case CG_INT64:return "dword";
+ case CG_FLOAT32:return "dword";
+ case CG_FLOAT64:return "qword";
+ }
+ cout<<"Unrcognized type:"<<type<<endl;
+ assert(0);
+ return 0;
+}
+
+CGMem *CGFrame_X86::tmpMem( int type ){
+ if( !tmp_mem ){
+ local_sz+=8;
+ tmp_mem=-local_sz;
+ }
+ return mem(type,ebp,tmp_mem);
+}
+
+CGMem *CGFrame_X86::optMem( CGMem *e,char *buf ){
+
+ CGBop *t=e->exp->bop();
+
+ if( !t ) return 0;
+
+ if( t->op!=CG_ADD && t->op!=CG_SUB ) return 0;
+
+ char c=t->op==CG_ADD ? '+' : '-';
+
+ CGBop *q=t->rhs->bop();
+ if( q && q->op==CG_MUL ){
+ if( CGLit *n=q->rhs->lit() ){
+ int f=n->int_value;
+ if( f==2 || f==4 || f==8 ){
+ char x_buf[256];
+ CGExp *x=genExp( t->lhs,x_buf,EA_IMM );
+ CGReg *y=genExp( q->lhs );
+ //x+y*v
+ const char *tm=e->offset ? "%s [%s%c'%i*%i+%i]" : "%s [%s%c'%i*%i]";
+ sprintf( buf,tm,x86size(e->type),x_buf,c,y->id,f,e->offset );
+
+ return mem(e->type,bop(t->op,x,bop(CG_MUL,y,n)),e->offset);
+ }
+ }
+ }
+
+ char x_buf[256],y_buf[256];
+
+ CGExp *x=genExp( t->lhs,x_buf,EA_IMM );
+ CGExp *y=genExp( t->rhs,y_buf,EA_IMM );
+
+ const char *tm=e->offset ? "%s [%s%c%s+%i]" : "%s [%s%c%s]";
+
+ sprintf( buf,tm,x86size(e->type),x_buf,c,y_buf,e->offset );
+
+ return mem(e->type,bop(t->op,x,y),e->offset);
+}
+
+bool CGFrame_X86::optMov( CGExp *lhs,CGExp *rhs ){
+
+ if( !lhs->mem() ) return false;
+
+ if( lhs->isfloat() ) return false;
+
+ CGBop *t=rhs->bop();
+ if( !t ) return false;
+
+ const char *op;
+ switch( t->op ){
+ case CG_ADD:op="add";break;
+ case CG_SUB:op="sub";break;
+ case CG_ORL:op="or";break;
+ case CG_AND:op="and";break;
+ case CG_XOR:op="xor";break;
+ default:return false;
+ }
+
+ if( !lhs->equals(t->lhs) ) return false;
+
+ char x_buf[256];
+ CGExp *x=genExp( lhs,x_buf,EA_MEM );
+
+ if( CGLit *y=t->rhs->lit() ){
+ int n=y->int_value;
+ const char *q=0;
+ if( t->op==CG_ADD ){
+ if( n==1 ) q="inc";
+ else if( n==-1 ) q="dec";
+ }else if( t->op==CG_SUB ){
+ if( n==1 ) q="dec";
+ else if( n==-1 ) q="inc";
+ }
+ if( q ){
+ gen( mov(x,bop(t->op,x,y)),"\t%s\t%s\n",q,x_buf );
+ return true;
+ }
+ }
+
+ char y_buf[256];
+ CGExp *y=genExp( t->rhs,y_buf,x->reg() ? EA_MEM|EA_IMM : EA_IMM );
+
+ gen( mov(x,bop(t->op,x,y)),"\t%s\t%s,%s\n",op,x_buf,y_buf );
+
+ return true;
+}
+
+CGReg *CGFrame_X86::genExp( CGExp *e ){
+ if( CGReg *t=e->reg() ){
+ return t;
+ }else if( CGMem *t=e->mem() ){
+ return genLoad( t );
+ }else if( CGLea *t=e->lea() ){
+ return genLea( t );
+ }else if( CGCvt *t=e->cvt() ){
+ return genCvt( t );
+ }else if( CGUop *t=e->uop() ){
+ return genUop( t );
+ }else if( CGBop *t=e->bop() ){
+ return genBop( t );
+ }else if( CGScc *t=e->scc() ){
+ return genScc( t );
+ }else if( CGJsr *t=e->jsr() ){
+ return genJsr( t );
+ }else if( CGLit *t=e->lit() ){
+ return genLit( t );
+ }else if( CGSym *t=e->sym() ){
+ return genSym( t );
+ }else if( CGFrm *t=e->frm() ){
+ return genFrm( t );
+ }
+ assert(0);
+ return 0;
+}
+
+CGMem *CGFrame_X86::genMem( CGMem *e,char *buf ){
+ if( CGMem *t=optMem(e,buf) ) return t;
+ char t_buf[256];
+ CGExp *t=genExp(e->exp,t_buf,EA_IMM );
+ const char *tm=e->offset ? "%s [%s%+i]" : "%s [%s]";
+ sprintf( buf,tm,x86size(e->type),t_buf,e->offset );
+ return mem( e->type,t,e->offset );
+}
+
+CGExp *CGFrame_X86::genExp( CGExp *e,char *buf,int mask ){
+
+ if( mask & EA_IMM ){
+ if( CGLit *t=e->lit() ){
+ if( t->isint() ){
+// sprintf( buf,FMTI64,t->int_value );
+ strcpy( buf,fromint( t->int_value ).c_str() );
+ return e;
+ }
+ }
+ if( CGSym *t=e->sym() ){
+ sprintf( buf,"%s",t->value.c_str() );
+ return e;
+ }
+ }
+ if( mask & EA_MEM ){
+ if( CGLit *t=e->lit() ){
+ if( t->type==CG_FLOAT32 ){
+ CGDat *d=dat();
+ d->push_back(t);
+ return genMem( mem(CG_FLOAT32,d,0),buf );
+ }
+ }
+ if( CGMem *t=e->mem() ){
+ if( t->type!=CG_INT8 && t->type!=CG_INT16 ){
+ return genMem( t,buf );
+ }
+ }
+ }
+ CGReg *r=genExp(e);
+ sprintf( buf,"'%i",r->id );
+ return r;
+}
+
+CGReg *CGFrame_X86::genLoad( CGMem *e ){
+
+ char buf[256];
+ e=genMem( e,buf );
+ const char *zx=(e->type==CG_INT8 || e->type==CG_INT16) ? "zx" : "";
+
+ CGReg *r=reg(e->type);
+ gen( mov(r,e),
+ "\tmov%s\t'%i,%s\n",zx,r->id,buf );
+
+ return r;
+}
+
+void CGFrame_X86::genCopy( CGReg *r,CGReg *t ){
+ if( r->id==t->id ) return;
+
+ gen( mov(r,t),"\tmov\t'%i,'%i\n",r->id,t->id );
+}
+
+void CGFrame_X86::genMov( CGExp *lhs,CGExp *rhs ){
+ if( lhs->equals(rhs) ) return;
+
+ char lhs_buf[256];
+ CGMem *lhs_mem=lhs->mem();
+ CGReg *lhs_reg=lhs->reg();
+
+ if( lhs_reg ){
+ sprintf( lhs_buf,"'%i",lhs_reg->id );
+ }else{
+ lhs=lhs_mem=genMem( lhs_mem,lhs_buf );
+ }
+
+ if( CGBop *t=rhs->bop() ){
+ if( t->lhs->equals(lhs) ){
+ if( t->isint() ){
+ const char *op=0;
+ switch( t->op ){
+ case CG_ADD:op="add";break;
+ case CG_SUB:op="sub";break;
+ case CG_ORL:op="or";break;
+ case CG_AND:op="and";break;
+ case CG_XOR:op="xor";break;
+ }
+ if( op ){
+ char rhs_buf[256];
+ int rhs_ea=EA_IMM;
+ if( lhs_reg ) rhs_ea|=EA_MEM;
+ rhs=genExp( t->rhs,rhs_buf,rhs_ea );
+ gen( mov(lhs,bop(t->op,lhs,rhs)),
+ "\t%s\t%s,%s\n",op,lhs_buf,rhs_buf );
+ return;
+ }
+ switch( t->op ){
+ case CG_SHL:op="shl";break;
+ case CG_SHR:op="shr";break;
+ case CG_SAR:op="sar";break;
+ }
+ if( op ){
+ char rhs_buf[256];
+ rhs=genExp( t->rhs,rhs_buf,EA_IMM );
+ if( CGReg *r=rhs->reg() ){
+ if( r->id!=ECX ){
+ genMov( ecx,r );
+ rhs=ecx;
+ }
+ strcpy( rhs_buf,"cl" );
+ }
+ gen( mov(lhs,bop(t->op,lhs,rhs)),
+ "\t%s\t%s,%s\n",op,lhs_buf,rhs_buf );
+ return;
+ }
+ }else if( lhs_reg && t->isfloat() ){
+ const char *op=0;
+ switch( t->op ){
+ case CG_ADD:op="fadd";break;
+ case CG_SUB:op="fsub";break;
+ case CG_MUL:op="fmul";break;
+ case CG_DIV:op="fdiv";break;
+ }
+ if( op ){
+ int rhs_ea=0;
+ char rhs_buf[256];
+ if( lhs_reg ) rhs_ea|=EA_MEM;
+ rhs=genExp( t->rhs,rhs_buf,rhs_ea );
+ gen( mov(lhs,bop(t->op,lhs,rhs)),
+ "\t%s\t%s,%s\n",op,lhs_buf,rhs_buf );
+ return;
+ }
+ }
+ }
+ }
+
+ char rhs_buf[256];
+ int rhs_ea=EA_IMM;
+ if( lhs_reg ) rhs_ea|=EA_MEM;
+ rhs=genExp( rhs,rhs_buf,rhs_ea );
+
+ if( lhs_mem && (lhs->type==CG_INT8 || lhs->type==CG_INT16) ){
+ if( CGReg *r=rhs->reg() ){
+ if( r->id!=EAX ){
+ genMov( eax,cvt(CG_INT32,rhs) );
+ rhs=cvt(lhs->type,eax);
+ }
+ strcpy( rhs_buf,lhs->type==CG_INT8 ? "al" : "ax" );
+ }
+ }
+
+ gen( mov(lhs,rhs),
+ "\tmov\t%s,%s\n",lhs_buf,rhs_buf );
+}
+
+CGReg *CGFrame_X86::genLea( CGLea *t ){
+
+ CGReg *r=reg(t->type);
+ CGMem *m=t->exp->mem();
+
+ assert( m );
+
+ char buf[256];
+ m=genMem( m,buf );
+ gen( mov(r,lea(m)),"\tlea\t'%i,%s\n",r->id,buf );
+ return r;
+}
+
+CGReg *CGFrame_X86::genCvt( CGCvt *t ){
+ CGReg *r;
+ if( t->isint() && t->exp->isint() ){
+ //int to int
+ r=reg(t->type);
+ char buf[256];
+ CGExp *exp=genExp(t->exp,buf,EA_IMM|EA_MEM);
+ if( r->type==CG_INT8 && t->exp->type!=CG_INT8 ){
+ gen( mov(r,cvt(r->type,exp)),
+ "\tmov\t'%i,%s\n"
+ "\tand\t'%i,0xff\n",
+ r->id,buf,r->id );
+ }else if( t->type==CG_INT16 && (t->exp->type==CG_INT32 || t->exp->type==CG_PTR) ){
+ gen( mov(r,cvt(r->type,exp)),
+ "\tmov\t'%i,%s\n"
+ "\tand\t'%i,0xffff\n",
+ r->id,buf,r->id );
+ }else{
+ gen( mov(r,cvt(r->type,exp)),
+ "\tmov\t'%i,%s\n",
+ r->id,buf );
+ }
+ }else{
+ r=reg(t->type);
+ CGReg *exp=genExp(t->exp);
+ gen( mov(r,cvt(r->type,exp)),
+ "\tmov\t'%i,'%i\n",r->id,exp->id );
+ }
+ return r;
+}
+
+CGReg *CGFrame_X86::genUop( CGUop *t ){
+
+ const char *op=0;
+
+ switch( t->op ){
+ case CG_NEG:op="neg";break;
+ case CG_NOT:assert(t->isint());op="not";break;
+ default:assert(0);
+ }
+
+ CGReg *r=reg(t->type);
+ genMov( r,t->exp );
+ gen( mov(r,uop(t->op,r)),"\t%s\t'%i\n",op,r->id );
+ return r;
+}
+
+static int shifter( int n ){
+ int k;
+ for( k=0;k<32;++k ) if( (1<<k)==n ) return k;
+ return -1;
+}
+
+CGReg *CGFrame_X86::genBop( CGBop *t ){
+
+ if( t->isint() && (t->op==CG_MUL || t->op==CG_DIV) ){
+ if( CGLit *c=t->rhs->lit() ){
+ int i=c->int_value;
+ if( t->op==CG_MUL ){
+ int n=shifter(i);
+ if( n!=-1 ){
+ return genBop( bop(CG_SHL,t->lhs,lit(n)) );
+ }
+ }else if( t->op==CG_DIV ){
+ int n=shifter(i);
+ if( n!=-1 ){
+ genMov( eax,t->lhs );
+ gen( xop(XOP_CDQ,edx,eax),"\tcdq\n" );
+ CGExp *e=edx;
+ e=bop(CG_AND,edx,lit(i-1));
+ e=bop(CG_ADD,eax,e);
+ e=bop(CG_SAR,e,lit(n));
+ return genExp(e);
+ }
+ }
+ }
+ }
+
+ CGReg *r=reg(t->type);
+
+ const char *op=0;
+
+ if( t->isfloat() ){
+ switch( t->op ){
+ case CG_ADD:op="fadd";break;
+ case CG_SUB:op="fsub";break;
+ case CG_MUL:op="fmul";break;
+ case CG_DIV:op="fdiv";break;
+ }
+ }else{
+ switch( t->op ){
+ case CG_ADD:op="add";break;
+ case CG_SUB:op="sub";break;
+ case CG_MUL:op="imul";break;
+ case CG_AND:op="and";break;
+ case CG_ORL:op="or";break;
+ case CG_XOR:op="xor";break;
+ }
+ }
+
+ if( op ){
+ genMov( r,t->lhs );
+
+ char buf[256];
+ CGExp *rhs=genExp( t->rhs,buf,EA_MEM|EA_IMM );
+
+ gen( mov(r,bop(t->op,r,rhs)),
+ "\t%s\t'%i,%s\n",op,r->id,buf );
+ return r;
+ }
+
+ assert( t->isint() );
+
+ switch( t->op ){
+ case CG_SHL:op="shl";break;
+ case CG_SHR:op="shr";break;
+ case CG_SAR:op="sar";break;
+ }
+ if( op ){
+ genMov(r,t->lhs);
+
+ if( CGLit *rhs=t->rhs->lit() ){
+// gen( mov(r,bop(t->op,r,rhs)),
+// "\t%s\t'%i," FMTI64 "\n",op,r->id,rhs->int_value );
+ char buf[64];
+ strcpy( buf,fromint( rhs->int_value ).c_str() );
+ gen( mov(r,bop(t->op,r,rhs)),
+ "\t%s\t'%i,%s\n",op,r->id,buf );
+ }else{
+ genMov( ecx,t->rhs );
+ gen( mov(r,bop(t->op,r,ecx)),
+ "\t%s\t'%i,cl\n",op,r->id );
+ }
+ return r;
+ }
+ switch( t->op ){
+ case CG_MOD:case CG_DIV:break;
+ default:assert(0);
+ }
+
+ char buf[256];
+ CGExp *rhs=genExp( t->rhs,buf,EA_MEM );
+
+ CGAsm *as;
+ if( t->op==CG_MOD ){
+ genMov( eax,t->lhs );
+ gen( xop(XOP_CDQ,edx,eax),"\tcdq\n" );
+ as=gen( mov(edx,bop(CG_MOD,eax,rhs)),"\tidiv\t%s\n",buf );
+ as->use.insert( EDX );
+ as->def.insert( EAX );
+ genMov( r,edx );
+
+// genMov( eax,t->lhs );
+// as=gen( mov(edx,bop(CG_MOD,eax,rhs)),"\tcdq\n\tidiv\t%s\n",buf );
+// as->def.insert( EAX );
+// genMov( r,edx );
+ }else{
+ genMov( eax,t->lhs );
+ gen( xop(XOP_CDQ,edx,eax),"\tcdq\n" );
+ as=gen( mov(eax,bop(CG_DIV,eax,rhs)),"\tidiv\t%s\n",buf );
+ as->use.insert( EDX );
+ as->def.insert( EDX );
+ genMov( r,eax );
+
+// genMov( eax,t->lhs );
+// as=gen( mov(eax,bop(CG_DIV,eax,rhs)),"\tcdq\n\tidiv\t%s\n",buf );
+// as->def.insert( EDX );
+// genMov( r,eax );
+ }
+ return r;
+}
+
+CGReg *CGFrame_X86::genScc( CGScc *t ){
+
+ CGReg *lhs=genExp( t->lhs );
+
+ if( lhs->isfloat() ){
+ CGReg *rhs=genExp( t->rhs );
+ gen( mov(eax,scc(t->cc,lhs,rhs)),"" );
+ }else{
+ char rhs_buf[256];
+ CGExp *rhs=genExp( t->rhs,rhs_buf,EA_MEM|EA_IMM );
+
+ gen( mov(eax,scc(t->cc,lhs,rhs)),
+ "\tcmp\t'%i,%s\n"
+ "\tset%s\tal\n"
+ "\tmovzx\teax,al\n",lhs->id,rhs_buf,x86cc(t->cc) );
+ }
+
+ CGReg *r=reg(CG_INT32);
+ genMov( r,eax );
+ return r;
+}
+
+CGReg *CGFrame_X86::genJsr( CGJsr *t ){
+
+ if( env_platform=="macos" ){
+ return genMacJsr( t );
+ }
+
+ int k,arg_sz=0;
+
+ CGExp *ea=t->exp;
+
+ for( k=0;k<t->args.size();++k ){
+ arg_sz+=t->args[k]->type==CG_FLOAT64 ? 8 : 4;
+ }
+ if( CGVfn *p=ea->vfn() ){
+ arg_sz+=p->self->type==CG_FLOAT64 ? 8 : 4;
+ }
+
+ for( k=t->args.size()-1;k>=0;--k ){
+ genPush( t->args[k] );
+ }
+ if( CGVfn *p=ea->vfn() ){
+ //put 'this' on stack
+ genPush( p->self );
+ ea=p->exp;
+ }
+
+ char buf[256];
+ ea=genExp( ea,buf,EA_MEM|EA_IMM );
+
+ CGReg *dst=t->isfloat() ? fp0 : eax;
+
+ CGAsm *as=gen( mov(dst,jsr(t->type,t->call_conv,ea)),"\tcall\t%s\n",buf );
+
+ as->def.insert(EAX);as->def.insert(EDX);as->def.insert(ECX);
+ as->def.insert(FP0);as->def.insert(FP1);as->def.insert(FP2);
+ as->def.insert(FP3);as->def.insert(FP4);as->def.insert(FP5);
+ as->def.insert(FP6);
+
+ if( t->call_conv==CG_CDECL ){
+ genPop( lit(arg_sz) );
+ }else{
+ ++extern_jsrs;
+
+ }
+
+ CGReg *r=reg(t->type);
+ genMov( r,dst );
+ return r;
+}
+
+static int argSize( CGExp *e ){
+ return e->type==CG_FLOAT64 ? 8 : 4;
+}
+
+static int paramSize( CGJsr *t ){
+ int i,sz=0;
+ if( CGVfn *p=t->exp->vfn() ) sz+=argSize( p->self );
+ for( i=0;i<t->args.size();++i ) sz+=argSize( t->args[i] );
+ return sz;
+}
+
+struct MaxParamSizeVisitor : public CGVisitor{
+ int size;
+
+ MaxParamSizeVisitor():size(0){}
+
+ CGExp *visit( CGExp *e ){
+ CGJsr *t=e->jsr();
+ if( !t ) return e;
+ int sz=paramSize( t );
+ if( sz>size ) size=sz;
+ return e;
+ }
+};
+
+static int maxParamSize( CGExp *e,int sz ){
+ MaxParamSizeVisitor v;
+ e->visit(v);
+ return v.size>sz ? v.size : sz;
+}
+
+CGReg *CGFrame_X86::genMacJsr( CGJsr *t ){
+
+///*
+ int i;
+ vector<int> maxszs;
+ vector<CGExp*> args;
+ vector<CGMov*> movs;
+
+ CGExp *ea=t->exp,*self=0;
+ if( CGVfn *p=ea->vfn() ){
+ ea=p->exp;
+ self=p->self;
+ }
+
+ args.push_back( ea );
+ if( self ) args.push_back( self );
+ for( i=0;i<t->args.size();++i ){
+ args.push_back( t->args[i] );
+ }
+
+ int maxsz=0;
+ for( i=0;i<args.size();++i ){
+ maxszs.push_back( maxsz );
+ maxsz=maxParamSize( args[i],maxsz );
+ }
+
+ char buf[256];
+ int offset=paramSize( t );
+ if( offset>param_sz ) param_sz=offset;
+
+ for( i=args.size()-1;i>=0;--i ){
+ if( i ){
+ CGExp *arg=args[i];
+ offset-=argSize( arg );
+ CGExp *lhs=mem( arg->type,esp,offset );
+ CGExp *rhs=genExp( args[i],buf,EA_IMM );
+ movs.push_back( mov(lhs,rhs) );
+ }else{
+ ea=genExp( ea,buf,EA_MEM|EA_IMM );
+ }
+ bool again=true;
+ vector<CGMov*>::iterator it;
+ while( again ){
+ again=false;
+ for( it=movs.begin();it!=movs.end();++it ){
+ CGMov *t=*it;
+ if( t->lhs->mem()->offset>=maxszs[i] ){
+ genMov( t->lhs,t->rhs );
+ movs.erase( it );
+ again=true;
+ break;
+ }
+ }
+ }
+ }
+//*/
+/*
+ vector<CGExp*> args;
+
+ int k,arg_sz=0;
+
+ for( k=t->args.size()-1;k>=0;--k ){
+ CGExp *arg=t->args[k];
+ args.push_back( genExp(t->args[k]) );
+ }
+
+ CGExp *ea=t->exp;
+
+ if( CGVfn *t=ea->vfn() ){
+ args.push_back( genExp(t->self) );
+ ea=t->exp;
+ }
+
+ char buf[256];
+ ea=genExp( ea,buf,EA_MEM|EA_IMM );
+
+ for( k=args.size()-1;k>=0;--k ){
+ CGExp *arg=args[k],*p;
+ p=mem( arg->type,esp,arg_sz );
+ arg_sz+=(arg->type==CG_FLOAT64) ? 8 : 4;
+ genMov( p,arg );
+ args[k]=p;
+ }
+
+ if( arg_sz>param_sz ) param_sz=arg_sz;
+*/
+
+ CGReg *dst=t->isfloat() ? fp0 : eax;
+
+ CGAsm *as=gen( mov(dst,jsr(t->type,t->call_conv,ea)),"\tcall\t%s\n",buf );
+
+ as->def.insert(EAX);as->def.insert(EDX);as->def.insert(ECX);
+ as->def.insert(FP0);as->def.insert(FP1);as->def.insert(FP2);
+ as->def.insert(FP3);as->def.insert(FP4);as->def.insert(FP5);
+ as->def.insert(FP6);
+
+ CGReg *r=reg( t->type );
+ genMov( r,dst );
+ return r;
+}
+
+CGReg *CGFrame_X86::genLit( CGLit *t ){
+
+ CGReg *r=reg(t->type);
+
+ if( t->isfloat() ){
+ double val=t->float_value;
+ if( val==0.0 || val==1.0 ){
+ gen( mov(r,t),"\tmov\t'%i,%f\n",r->id,t->float_value );
+ }else{
+ CGDat *d=dat();
+ d->push_back(t);
+ genMov( r,mem(t->type,d,0) );
+ }
+ }else if( t->int_value==0 ){
+ gen( mov(r,t),"\txor\t'%i,'%i\n",r->id,r->id );
+ }else{
+// gen( mov(r,t),"\tmov\t'%i," FMTI64 "\n",r->id,t->int_value );
+ char buf[64];
+ strcpy( buf,fromint( t->int_value ).c_str() );
+ gen( mov(r,t),"\tmov\t'%i,%s\n",r->id,buf );
+ }
+ return r;
+}
+
+CGReg *CGFrame_X86::genSym( CGSym *t ){
+ CGReg *r=reg(t->type);
+ gen( mov(r,t),"\tmov\t'%i,%s\n",r->id,t->value.c_str() );
+ return r;
+}
+
+CGReg *CGFrame_X86::genFrm( CGFrm *t ){
+ CGReg *r=reg(CG_PTR);
+ genMov( r,ebp );
+ return r;
+}
+
+void CGFrame_X86::genPush( CGExp *e ){
+ if( e->type==CG_FLOAT32 ){
+ if( CGLit *t=e->lit() ){
+ float n=t->float_value;
+ e=lit( *(int*)&n );
+ }
+ genPush4(e);
+ }else if( e->type==CG_FLOAT64 ){
+ genPush8(e);
+ }else if( e->type==CG_INT8 || e->type==CG_INT16 ){
+ if( e->mem() ) e=genExp(e);
+ genPush4(e);
+ }else{
+ genPush4(e);
+ }
+}
+
+void CGFrame_X86::genPush4( CGExp *e ){
+ int ea=(e->type==CG_FLOAT64) ? 0 : EA_MEM|EA_IMM;
+ char buf[256];
+ e=genExp( e,buf,ea );
+ gen( xop(XOP_PUSH4,0,e),"\tpush\t%s\n",buf );
+}
+
+void CGFrame_X86::genPush8( CGExp *e ){
+ CGReg *r=genExp( e );
+ gen( xop(XOP_PUSH8,0,r),"\tpush\t'%i\n",r->id );
+}
+
+void CGFrame_X86::genPop( CGExp *e ){
+
+ if( CGLit *t=e->lit() ){
+ if( !t->int_value ) return;
+ }
+
+ char buf[256];
+ e=genExp( e,buf,EA_MEM|EA_IMM );
+
+ if( buf[0]=='-' ){
+ gen( xop(XOP_POP,0,e),"\tsub\tesp,%s\n",buf+1 );
+ }else{
+ gen( xop(XOP_POP,0,e),"\tadd\tesp,%s\n",buf );
+ }
+}
+
+void CGFrame_X86::genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *tgt ){
+
+ //use scc for FP
+ if( lhs->isfloat() ){
+ lhs=genExp(lhs);
+ rhs=genExp(rhs);
+ gen( mov(eax,scc(cc,lhs,rhs)),"" );
+ cc=CG_NE;
+ lhs=eax;
+ rhs=lit0;
+ }
+
+ char lhs_buf[256],rhs_buf[256];
+ lhs=genExp(lhs,lhs_buf,EA_MEM);
+ rhs=genExp(rhs,rhs_buf,lhs->mem() ? EA_IMM : EA_MEM|EA_IMM);
+ gen(
+ bcc(cc,lhs,rhs,tgt),
+ "\tcmp\t%s,%s\n"
+ "\tj%s\t%s\n",
+ lhs_buf,rhs_buf,x86cc(cc),tgt->value.c_str() );
+}
+
+void CGFrame_X86::genRet( CGExp *e ){
+ CGReg *r=0;
+ if( e ){
+ r=e->isfloat() ? fp0 : eax;
+ genMov(r,e);
+ }
+ CGAsm *as;
+ if( fun->call_conv==CG_CDECL ){
+ as=gen( ret(r),"\tret\n" );
+ }else{
+ as=gen( ret(r),"\tret\t%i\n",arg_sz );
+ }
+ as->use.insert( EBP );
+}
+
+string CGFrame_X86::fixSym( string id ){
+ if( env_platform=="linux" ) return id;
+ return "_"+id;
+}
+
+void CGFrame_X86::genStm( CGStm *s ){
+
+ if( CGAti *t=s->ati() ){
+ char buf[256];
+ CGMem *mem=genMem( t->mem,buf );
+ gen( ati(mem),"\tinc\t%s\n",buf );
+ }else if( CGAtd *t=s->atd() ){
+ char buf[256];
+ CGMem *mem=genMem( t->mem,buf );
+ gen( atd(mem,t->sym),"\tdec\t%s\n\tjnz\t%s\n",buf,t->sym->value.c_str() );
+ }else if( CGMov *t=s->mov() ){
+ genMov( t->lhs,t->rhs );
+ }else if( CGLab *t=s->lab() ){
+ gen( t,"%s:\n",t->sym->value.c_str() );
+ }else if( CGBra *t=s->bra() ){
+ gen( t,"\tjmp\t%s\n",t->sym->value.c_str() );
+ }else if( CGBcc *t=s->bcc() ){
+ genBcc( t->cc,t->lhs,t->rhs,t->sym );
+ }else if( CGEva *t=s->eva() ){
+ if( t->exp->dat() ){
+ gen( t,"" );
+ }else{
+ genExp( t->exp );
+ }
+ }else if( CGRem *t=s->rem() ){
+ gen( t,"\t;%s\n",t->comment.c_str() );
+ }else if( CGRet *t=s->ret() ){
+ genRet( t->exp );
+ }else if( CGXop *t=s->xop() ){
+ switch( t->op ){
+ case XOP_PUSH4:genPush4(t->exp);break;
+ case XOP_PUSH8:genPush8(t->exp);break;
+ case XOP_POP:genPop(t->exp);break;
+ case XOP_CDQ:break;
+ default:assert(0);
+ }
+ }else{
+ assert(0);
+ }
+}
+
+void CGFrame_X86::genFun(){
+
+ if( CGExp *t=fun->self ){
+ //get 'this' from stack
+ genMov( t,mem(CG_PTR,ebp,arg_sz+8) );
+ arg_sz+=4;
+ }
+
+ int k;
+ for( k=0;k<fun->args.size();++k ){
+ //get args from stack
+ CGExp *t=fun->args[k];
+ int n=t->type==CG_FLOAT64 ? 8 :4;
+ genMov(t,mem(t->type,ebp,arg_sz+8));
+ arg_sz+=n;
+ }
+
+ for( k=0;k<fun->stms.size();++k ){
+ genStm( fun->stms[k] );
+ }
+}
+
+CGMem *CGFrame_X86::allocLocal( int type ){
+ int n=(type==CG_FLOAT64 || type==CG_INT64) ? 8 : 4;
+ local_sz+=n;
+ return mem(type,ebp,-local_sz);
+}
+
+CGExp *CGFrame_X86::allocSpill( CGReg *r ){
+ int sz=8;
+ if( fun->self ){
+ if( r->equals(fun->self) ) return mem(CG_PTR,ebp,sz);
+ sz+=4;
+ }
+ int k;
+ for( k=0;k<fun->args.size();++k ){
+ CGExp *t=fun->args[k];
+ if( r->equals(t) ) return mem(t->type,ebp,sz);
+ sz+=(t->type==CG_FLOAT64) ? 8 : 4;
+ }
+ return allocLocal( r->type );
+}
+
+void CGFrame_X86::finish(){
+ fixFp();
+}
+
+CGFrame_X86::CGFrame_X86( CGFun *f,CGModule_X86 *m ):CGFrame(f),mod_x86(m){
+
+ arg_sz=0;
+ tmp_mem=0;
+ param_sz=0;
+ local_sz=0;
+ extern_jsrs=0;
+
+ //int types map to reg bank 0
+ reg_banks[CG_PTR]=0;
+ reg_banks[CG_INT8]=0;
+ reg_banks[CG_INT16]=0;
+ reg_banks[CG_INT32]=0;
+ reg_banks[CG_INT64]=-1; //no int64 regs!
+
+ //int regs
+ eax=reg( CG_INT32,0,0 );
+ edx=reg( CG_INT32,0,1 );
+ ecx=reg( CG_INT32,0,2 );
+ ebx=reg( CG_INT32,0,3 );
+ esi=reg( CG_INT32,0,4 );
+ edi=reg( CG_INT32,0,5 );
+ ebp=reg( CG_INT32,0,6 );
+ esp=reg( CG_INT32,0,7 );
+
+ reg_masks[0]=0x3f; //no ebp or esp!
+
+ //int reg names
+ reg_names[0].push_back( "eax" );
+ reg_names[0].push_back( "edx" );
+ reg_names[0].push_back( "ecx" );
+ reg_names[0].push_back( "ebx" );
+ reg_names[0].push_back( "esi" );
+ reg_names[0].push_back( "edi" );
+ reg_names[0].push_back( "ebp" );
+ reg_names[0].push_back( "esp" );
+
+ //float types map to bank 1
+ reg_banks[CG_FLOAT32]=1;
+ reg_banks[CG_FLOAT64]=1;
+
+ //float regs
+ fp0=reg( CG_FLOAT64,0,0 );
+ fp1=reg( CG_FLOAT64,0,1 );
+ fp2=reg( CG_FLOAT64,0,2 );
+ fp3=reg( CG_FLOAT64,0,3 );
+ fp4=reg( CG_FLOAT64,0,4 );
+ fp5=reg( CG_FLOAT64,0,5 );
+ fp6=reg( CG_FLOAT64,0,6 );
+
+ reg_masks[1]=0x7f; //no f7!
+
+ //float reg names
+ reg_names[1].push_back( "fp0" );
+ reg_names[1].push_back( "fp1" );
+ reg_names[1].push_back( "fp2" );
+ reg_names[1].push_back( "fp3" );
+ reg_names[1].push_back( "fp4" );
+ reg_names[1].push_back( "fp5" );
+ reg_names[1].push_back( "fp6" );
+}
--- /dev/null
+
+#ifndef CGFRAME_X86_H
+#define CGFRAME_X86_H
+
+#include "cgframe.h"
+
+struct CGModule_X86;
+
+struct CGFrame_X86 : public CGFrame{
+
+ CGModule_X86 *mod_x86;
+
+ int arg_sz,param_sz,local_sz,tmp_mem,extern_jsrs;
+
+ enum{
+ EA_IMM=1,EA_MEM=2
+ };
+ enum{
+ XOP_CDQ=1,XOP_DIV,
+ XOP_PUSH4,XOP_PUSH8,XOP_POP
+ };
+ enum{
+ EAX,EDX,ECX,EBX,ESI,EDI,EBP,ESP,
+ FP0,FP1,FP2,FP3,FP4,FP5,FP6
+ };
+
+ CGReg *eax,*edx,*ecx,*ebx,*esi,*edi,*ebp,*esp;
+ CGReg *fp0,*fp1,*fp2,*fp3,*fp4,*fp5,*fp6;
+
+ CGMem* tmpMem( int type );
+
+ CGMem* optMem( CGMem *exp,char *buf );
+ bool optMov( CGExp *lhs,CGExp *rhs );
+
+ CGMem* genMem( CGMem *exp,char *buf );
+ CGExp* genExp( CGExp *exp,char *buf,int mask );
+
+ CGReg* genExp( CGExp *exp );
+ CGReg* genLea( CGLea *exp );
+ CGReg* genCvt( CGCvt *exp );
+ CGReg* genUop( CGUop *exp );
+ CGReg* genBop( CGBop *exp );
+ CGReg* genScc( CGScc *exp );
+ CGReg* genJsr( CGJsr *exp );
+ CGReg* genMacJsr( CGJsr *exp );
+ CGReg* genLit( CGLit *exp );
+ CGReg* genSym( CGSym *exp );
+ CGReg* genFrm( CGFrm *exp );
+
+ CGReg* genLoad( CGMem *exp );
+ void genStore( CGMem *mem,CGExp *exp );
+ void genCopy( CGReg *res,CGReg *exp );
+ void genMov( CGExp *lhs,CGExp *rhs );
+
+ void genPush( CGExp *exp );
+ void genPush4( CGExp *exp );
+ void genPush8( CGExp *exp );
+ void genPop( CGExp *exp );
+
+ void genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym );
+ void genRet( CGExp *exp );
+
+ void fixFp();
+
+ CGFrame_X86( CGFun *fun,CGModule_X86 *mod );
+
+ virtual string fixSym( string id );
+ virtual void genFun();
+ virtual void genStm( CGStm *stm );
+ virtual CGMem *allocLocal( int type );
+ virtual CGExp *allocSpill( CGReg *r );
+ virtual void finish();
+
+ static const char *x86cc( int cg_cc );
+ static const char *x86size( int cg_sz );
+};
+
+#endif
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgframe.h"
+#include "cgallocregs.h"
+#include "cgutil.h"
+#include "cgdebug.h"
+
+using namespace CG;
+
+static CGFun *func;
+static CGFrame *frame;
+static CGMem *i64_dummy;
+
+static void int32ToInt64( CGMem *m,CGExp *exp ){
+ func->stms.push_back( mov(frame->int64lo(m),exp) );
+ func->stms.push_back( mov(frame->int64hi(m),lit0) );
+}
+
+static CGExp *int64ToInt32( CGExp *exp ){
+ if( CGLit *t=exp->lit() ){
+ return lit((int)(t->int_value));
+ }else if( CGMem *t=exp->mem() ){
+ return frame->int64lo(t);
+ }
+ assert(0);
+ return 0;
+}
+
+static void genInt64Stms( CGMem *m,CGExp *exp ){
+ if( CGLit *t=exp->lit() ){
+ //mov i64,lit
+ CGLit *lo=lit( (int)(t->int_value) );
+ CGLit *hi=lit( (int)(t->int_value>>int64(32)) );
+ func->stms.push_back( mov(frame->int64lo(m),lo) );
+ func->stms.push_back( mov(frame->int64hi(m),hi) );
+ }else if( CGMem *t=exp->mem() ){
+ func->stms.push_back( mov(frame->int64lo(m),frame->int64lo(t)) );
+ func->stms.push_back( mov(frame->int64hi(m),frame->int64hi(t)) );
+ }else if( CGJsr *t=exp->jsr() ){
+ CGJsr *e=jsr(CG_INT32,t->call_conv,t->exp );
+ e->args.push_back( lea(m) );
+ for( int k=0;k<t->args.size();++k ) e->args.push_back( t->args[k] );
+ func->stms.push_back( eva(e) );
+ }else if( CGUop *t=exp->uop() ){
+ string f;
+ switch( t->op ){
+ case CG_NEG:f="bbLongNeg";break;
+ case CG_NOT:f="bbLongNot";break;
+ case CG_ABS:f="bbLongAbs";break;
+ case CG_SGN:f="bbLongSgn";break;
+ default:assert(0);
+ }
+ CGJsr *e=jsr(CG_INT32,f);
+ e->args.push_back( lea(m) );
+ e->args.push_back( t->exp );
+ func->stms.push_back( eva(e) );
+ }else if( CGBop *t=exp->bop() ){
+ string f;
+ switch( t->op ){
+ case CG_ADD:f="bbLongAdd";break;
+ case CG_SUB:f="bbLongSub";break;
+ case CG_MUL:f="bbLongMul";break;
+ case CG_DIV:f="bbLongDiv";break;
+ case CG_MOD:f="bbLongMod";break;
+ case CG_AND:f="bbLongAnd";break;
+ case CG_ORL:f="bbLongOrl";break;
+ case CG_XOR:f="bbLongXor";break;
+ case CG_SHL:f="bbLongShl";break;
+ case CG_SHR:f="bbLongShr";break;
+ case CG_SAR:f="bbLongSar";break;
+ case CG_MIN:f="bbLongMin";break;
+ case CG_MAX:f="bbLongMax";break;
+ default:assert(0);
+ }
+ CGJsr *e=jsr(CG_INT32,f);
+ e->args.push_back( lea(m) );
+ e->args.push_back( t->lhs );
+ e->args.push_back( t->rhs );
+ func->stms.push_back( eva(e) );
+ }else if( CGCvt *t=exp->cvt() ){
+ CGExp *e=t->exp;
+ switch( e->type ){
+ case CG_INT8: //int8 to int64
+ int32ToInt64(m,cvt(CG_INT32,e));
+ break;
+ case CG_INT16: //int16 to int64
+ int32ToInt64(m,cvt(CG_INT32,e));
+ break;
+ case CG_PTR: //ptr to int64
+ int32ToInt64(m,e);
+ break;
+ case CG_INT32: //int32 to int64
+ func->stms.push_back( eva(jsr(CG_INT32,"bbIntToLong",lea(m),e)) );
+ break;
+ case CG_INT64:
+ break;
+ case CG_FLOAT32://float32 to int64
+ func->stms.push_back( eva(jsr(CG_INT32,"bbFloatToLong",lea(m),cvt(CG_FLOAT64,e))) );
+ break;
+ case CG_FLOAT64://float64 to int64
+ func->stms.push_back( eva(jsr(CG_INT32,"bbFloatToLong",lea(m),e)) );
+ break;
+ default:
+ assert(0);
+ }
+ }else{
+ cout<<exp<<endl;
+ assert(0);
+ }
+}
+
+struct CGInt64StmFixer : public CGVisitor{
+ CGFrame *frame;
+
+ CGInt64StmFixer( CGFrame *f ):frame(f){}
+
+ CGStm *visit( CGStm *stm ){
+ if( CGMov *t=stm->mov() ){
+ if( t->lhs->type==CG_INT64 ){
+ CGMem *lhs=t->lhs->mem();
+ assert( lhs );
+ genInt64Stms( lhs,t->rhs );
+ return stm;
+ }
+ }else if( CGEva *t=stm->eva() ){
+ if( t->exp->type==CG_INT64 ){
+ if( !i64_dummy ) i64_dummy=frame->allocLocal( CG_INT64 );
+ genInt64Stms( i64_dummy,t->exp );
+ return stm;
+ }
+ }else if( CGRet *t=stm->ret() ){
+ if( frame->int64ret ){
+ CGMem *lhs=mem(CG_INT64,frame->int64ret,0);
+ genInt64Stms( lhs,t->exp );
+ func->stms.push_back( ret(0) );
+ return stm;
+ }
+ }else if( CGBcc *t=stm->bcc() ){
+ if( t->lhs->type==CG_INT64 ){
+ func->stms.push_back( bcc(CG_NE,scc(t->cc,t->lhs,t->rhs),lit0,t->sym) );
+ return stm;
+ }
+ }
+ func->stms.push_back( stm );
+ return stm;
+ }
+};
+
+struct CGInt64ExpFixer : public CGVisitor{
+ CGFrame *frame;
+ CGFun *fun;
+
+ CGInt64ExpFixer( CGFrame *f ):frame(f),fun(frame->fun){}
+
+ CGStm *visit( CGStm *stm ){
+ func->stms.push_back( stm );
+ return stm;
+ }
+
+ CGExp *visit( CGExp *exp ){
+ if( CGScc *t=exp->scc() ){
+ if( t->lhs->type!=CG_INT64 ) return exp;
+ string f;
+ switch( t->cc ){
+ case CG_LT:f="bbLongSlt";break;
+ case CG_GT:f="bbLongSgt";break;
+ case CG_LE:f="bbLongSle";break;
+ case CG_GE:f="bbLongSge";break;
+ case CG_EQ:f="bbLongSeq";break;
+ case CG_NE:f="bbLongSne";break;
+ default:assert(0);
+ }
+ CGJsr *e=jsr(CG_INT32,f,t->lhs,t->rhs);
+ return e;
+ }else if( CGCvt *t=exp->cvt() ){
+ CGExp *e=t->exp;
+ if( e->type==CG_INT64 ){
+ switch( t->type ){
+ case CG_INT8: //int64 to int8
+ return cvt(CG_INT8,int64ToInt32(e));
+ case CG_INT16: //int64 to int16
+ return cvt(CG_INT16,int64ToInt32(e));
+ case CG_INT32: //int64 to int32
+ return int64ToInt32(e);
+ case CG_INT64:
+ return e;
+ case CG_FLOAT32://int64 to float32
+ return cvt(CG_FLOAT32,jsr(CG_FLOAT64,"bbLongToFloat",e));
+ case CG_FLOAT64://int64 to float64
+ return jsr(CG_FLOAT64,"bbLongToFloat",e);
+ }
+ assert(0);
+ }
+ }
+ if( exp->type!=CG_INT64 ) return exp;
+ if( exp->uop() || exp->bop() || exp->jsr() || exp->cvt() ){
+ CGMem *m=frame->allocLocal( CG_INT64 );
+ genInt64Stms( m,exp );
+ return m;
+ }
+ return exp;
+ }
+};
+
+struct CGInt64ArgFixer : public CGVisitor{
+ CGFrame *frame;
+
+ CGInt64ArgFixer( CGFrame *f ):frame(f){}
+
+ CGExp *visit( CGExp *exp ){
+ if( CGJsr *t=exp->jsr() ){
+ int k;
+ for( k=0;k<t->args.size();++k ){
+ if( t->args[k]->type==CG_INT64 ) break;
+ }
+ if( k==t->args.size() ) return exp;
+ CGJsr *e=jsr( t->type,t->call_conv,t->exp );
+ for( k=0;k<t->args.size();++k ){
+ CGExp *arg=t->args[k];
+ if( arg->type!=CG_INT64 ){
+ e->args.push_back( arg );
+ continue;
+ }
+ if( CGMem *t=arg->mem() ){
+ e->args.push_back( frame->int64el(t,0) );
+ e->args.push_back( frame->int64el(t,4) );
+ }else if( CGLit *t=arg->lit() ){
+ assert( t->type==CG_INT64 );
+ int *p=(int*)&t->int_value;
+ e->args.push_back( lit(p[0]) );
+ e->args.push_back( lit(p[1]) );
+ }else{
+ cout<<arg<<endl;
+ assert(0);
+ }
+ }
+ return e;
+ }
+ return exp;
+ }
+};
+
+void CGFrame::fixInt64(){
+ ::func=fun;
+ ::frame=this;
+ ::i64_dummy=0;
+
+ int k;
+ vector<CGStm*> stms;
+
+ stms.clear();
+ stms.swap( func->stms );
+ CGInt64StmFixer stm_vis( this );
+ for( k=0;k<stms.size();++k ) stms[k]->visit( stm_vis );
+
+ stms.clear();
+ stms.swap( func->stms );
+ CGInt64ExpFixer exp_vis( this );
+ for( k=0;k<stms.size();++k ) stms[k]->visit( exp_vis );
+
+ CGInt64ArgFixer arg_vis( this );
+ func=visitFun( func,arg_vis );
+
+ fun=func;
+}
--- /dev/null
+
+#ifndef CGINT64_H
+#define CGINT64_H
+
+#include "cgframe.h"
+
+#endif
+
+
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgintset.h"
+
+using namespace std;
+
+int CGIntSet::insert( int n ){
+ int sz=size();
+ set<int>::insert(n);
+ return size()-sz;
+}
+
+int CGIntSet::insert( const CGIntSet &t ){
+ int sz=size();
+ const_iterator it;
+ for( it=t.begin();it!=t.end();++it ){
+ set<int>::insert( *it );
+ }
+ return size()-sz;
+}
+
+int CGIntSet::xinsert( const CGIntSet &t,const CGIntSet &p ){ //insert elements in t NOT in p
+ int sz=size();
+ const_iterator it;
+ for( it=t.begin();it!=t.end();++it ){
+ int n=*it;
+ if( !p.count(n) ) set<int>::insert(n);
+ }
+ return size()-sz;
+}
+
+int CGIntSet::erase( int n ){
+ return set<int>::erase(n);
+}
+
+int CGIntSet::erase( const CGIntSet &t ){
+ int sz=size();
+ const_iterator it;
+ for( it=t.begin();it!=t.end();++it ){
+ set<int>::erase( *it );
+ }
+ return sz-size();
+}
+int CGIntSet::xerase( const CGIntSet &t,const CGIntSet &p ){ //erase elements in t NOT in p
+ int sz=size();
+ const_iterator it;
+ for( it=t.begin();it!=t.end();++it ){
+ int n=*it;
+ if( !p.count(n) ) set<int>::erase(n);
+ }
+ return sz-size();
+}
+
+CGIntSet::iterator CGIntSet::erase( iterator it ){
+ iterator t=it++;
+ set<int>::erase(t);
+ return it;
+}
--- /dev/null
+
+#ifndef CGINTSET_H
+#define CGINTSET_H
+
+struct CGIntSet : std::set<int>{
+
+ int insert( int n );
+ int insert( const CGIntSet &t );
+ int xinsert( const CGIntSet &t,const CGIntSet &p );
+
+ int erase( int n );
+ int erase( const CGIntSet &t );
+ int xerase( const CGIntSet &t,const CGIntSet &p );
+
+ iterator erase( iterator it );
+};
+
+typedef CGIntSet::iterator CGIntIter;
+typedef CGIntSet::const_iterator CGIntCIter;
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgmodule.h"
+
+CGModule::CGModule( ostream &o ):out(o){
+}
+
+CGModule::~CGModule(){
+}
+
+CGFrame *CGModule::createFrame( CGFun *fun ){
+ CGFrame *f=frame(fun);
+ frames.push_back(f);
+ return f;
+}
+
+struct CGSymFinder : public CGVisitor{
+
+ CGModule *module;
+
+ CGSymFinder( CGModule *m ):module(m){}
+
+ CGExp *visit( CGExp *exp ){
+ if( CGSym *t=exp->sym() ){
+ if( CGDat *d=t->dat() ){
+ if( !module->dataSyms.count(d->value) ){
+ module->datas.push_back(d);
+ module->dataSyms.insert( d->value );
+ }
+ }
+ if( t->linkage==CG_IMPORT ) module->importSyms.insert( t->value );
+ else if( t->linkage==CG_EXPORT ) module->exportSyms.insert( t->value );
+
+ }
+ return exp;
+ }
+};
+
+void CGModule::emitModule(){
+
+ CGSymFinder vis(this);
+
+ int k;
+ for( k=0;k<frames.size();++k ){
+ CGFrame *f=frames[k];
+ CGSym *sym=f->fun->sym;
+ if( sym->linkage==CG_EXPORT ) exportSyms.insert( sym->value );
+ CGAsm *as;
+ for( as=f->assem.begin;as!=f->assem.end;as=as->succ ){
+ CGStm *t=as->stm;
+ if( !t ) continue;
+ t->visit( vis );
+ }
+ }
+
+ set<string>::iterator sym_it;
+
+ //header
+ emitHeader();
+
+ //imports
+ for( sym_it=importSyms.begin();sym_it!=importSyms.end();++sym_it ){
+ emitImport( *sym_it );
+ }
+
+ //exports
+ for( sym_it=exportSyms.begin();sym_it!=exportSyms.end();++sym_it ){
+ emitExport( *sym_it );
+ }
+
+ //frames
+ for( k=0;k<frames.size();++k ){
+ emitFrame( frames[k] );
+ }
+
+ //datas
+ for( k=0;k<datas.size();++k ){
+ emitData( datas[k] );
+ }
+
+ //footer
+ emitFooter();
+
+ out.flush();
+}
--- /dev/null
+
+#ifndef CGMODULE_H
+#define CGMODULE_H
+
+#include "cgframe.h"
+
+struct CGModule{
+ ostream& out;
+ vector<CGFrame*> frames;
+ vector<CGDat*> datas;
+
+ set<string> importSyms,exportSyms,dataSyms;
+
+ CGModule( ostream &out );
+ virtual ~CGModule();
+
+ CGFrame* createFrame( CGFun *f );
+ void emitModule();
+
+ virtual CGFrame*frame( CGFun *fun )=0;
+ virtual void emitHeader()=0;
+ virtual void emitImport( string t )=0;
+ virtual void emitExport( string t )=0;
+ virtual void emitFrame( CGFrame *frame )=0;
+ virtual void emitData( CGDat *dat )=0;
+ virtual void emitFooter()=0;
+};
+
+/*
+struct CGModule{
+
+ IdentSet externs;
+ IdentSet exports;
+ IdentSet imports;
+
+ std::set<CGDat*> datas;
+
+ virtual ~CGModule();
+
+ virtual void emit();
+
+ virtual CGFrame* createFrame( CGFun *fun )=0;
+ virtual void flush()=0;
+};
+*/
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+#include "cgdebug.h"
+
+#include "cgmodule_ppc.h"
+
+CGModule_PPC::CGModule_PPC( ostream &o ):CGModule(o),fp_const(0){
+}
+
+void CGModule_PPC::setSeg( string t ){
+ if( t==seg ) return;
+ seg=t;
+ out<<"\t."<<seg<<'\n';
+}
+
+CGFrame *CGModule_PPC::frame( CGFun *f ){
+ return new CGFrame_PPC( f,this );
+}
+
+void CGModule_PPC::emitHeader(){
+}
+
+void CGModule_PPC::emitImport( string t ){
+ out<<"\t.non_lazy_symbol_pointer\n";
+ out<<""<<t<<"$non_lazy_ptr:\n";
+ out<<"\t.indirect_symbol\t"<<t<<"\n";
+ out<<"\t.long\t0\n";
+}
+
+void CGModule_PPC::emitExport( string t ){
+ out<<"\t.globl\t"<<t<<'\n';
+}
+
+void CGModule_PPC::emitFrame( CGFrame *f ){
+
+ CGFrame_PPC *frame=dynamic_cast<CGFrame_PPC*>(f);
+ assert(frame);
+
+ setSeg( "text" );
+
+ //find callee-save regs
+ int k,max_int=12,max_flt=13;
+
+ for( k=64;k<frame->regs.size();++k ){
+ CGReg *r=frame->regs[k];
+ if( r->isfloat() ){
+ if( r->color>=14 && r->color<=31 && r->color>max_flt ) max_flt=r->color;
+ }else{
+ if( r->color>=13 && r->color<=31 && r->color>max_int ) max_int=r->color;
+ }
+ }
+
+ int int_save=max_int-12;
+ int flt_save=max_flt-13;
+ int save_sz=int_save*4+flt_save*8;
+
+ int stack_sz=24+frame->param_sz+frame->local_sz+save_sz;
+ stack_sz=(stack_sz+15)&~15;
+
+ //emit label
+ out<<frame->fun->sym->value<<":\n";
+
+ //setup frames
+ out<<"__LOCAL="<<(24+frame->param_sz)<<'\n';
+ out<<"__FRAME="<<stack_sz<<'\n';
+
+ //get link register
+ out<<"\tmflr\tr0\n";
+
+ //save float regs
+ for( k=0;k<flt_save;++k ){
+ out<<"\tstfd\tf"<<(k+14)<<","<<(-save_sz+int_save*4+k*8)<<"(r1)\n";
+ }
+ //save int regs
+ if( int_save ){
+ out<<"\tstmw\tr"<<(32-int_save)<<","<<(-save_sz)<<"(r1)\n";
+ }
+
+ //save link register
+ out<<"\tstw\tr0,8(r1)\n";
+
+ //allocate frame
+ out<<"\tstwu\tr1,"<<-stack_sz<<"(r1)\n";
+
+ CGAsm *as;
+ for( as=frame->assem.begin;as!=frame->assem.end;as=as->succ ){
+ if( as->stm->ret() ){
+ out<<"\tlwz\tr1,0(r1)\n";
+ out<<"\tlwz\tr0,8(r1)\n";
+ out<<"\tmtlr\tr0\n";
+ //restore int regs
+ if( int_save ){
+ out<<"\tlmw\tr"<<(32-int_save)<<","<<(-save_sz)<<"(r1)\n";
+ }
+ //restore float regs
+ for( int k=flt_save-1;k>=0;--k ){
+ out<<"\tlfd\tf"<<(k+14)<<","<<(-save_sz+int_save*4+k*8)<<"(r1)\n";
+ }
+ }
+
+ const char *p=as->assem;
+ if( !p ) continue;
+
+ out<<p;
+ }
+}
+
+void CGModule_PPC::emitData( CGDat *d ){
+
+ setSeg( "data" );
+
+ out<<"\t.align\t2\n";
+ out<<d->value<<":\n";
+
+ for( int k=0;k<d->exps.size();++k ){
+
+ CGExp *e=d->exps[k];
+
+ if( CGLit *t=e->lit() ){
+ if( t->type==CG_INT8 ){
+ out<<"\t.byte\t"<<unsigned(t->int_value)<<'\n';
+ }else if( t->type==CG_INT16 ){
+ out<<"\t.short\t"<<unsigned(t->int_value)<<'\n';
+ }else if( t->type==CG_INT32 ){
+ out<<"\t.long\t"<<int(t->int_value)<<'\n';
+ }else if( t->type==CG_INT64 ){
+ out<<"\t.long\t"<<int(t->int_value>>int64(32))<<','<<int(t->int_value)<<'\n';
+ }else if( t->type==CG_FLOAT32 ){
+ float f=t->float_value;
+ out<<"\t.long\t0x"<<hex<<*((int*)&f)<<dec<<'\n';
+ }else if( t->type==CG_FLOAT64 ){
+ double f=t->float_value;
+ out<<"\t.long\t0x"<<hex<<*((int*)&f+0)<<",0x"<<*((int*)&f+1)<<dec<<'\n';
+ }else if( t->type==CG_CSTRING ){
+ bstring s=t->string_value;
+ out<<"\t.asciz\t\"";
+ for( int k=0;k<s.size();++k ){
+ if( s[k]==34 ){
+ out<<"\\\"";
+ }else{
+ out<<(char)s[k];
+ }
+ }
+ out<<"\"\n";
+ }else if( t->type==CG_BSTRING ){
+ bstring s=t->string_value;
+ out<<"\t.long\t"<<s.size();
+ for( int k=0;k<s.size();++k ){
+ if( k%16 ) out<<','<<(unsigned)(unsigned short)s[k];
+ else out<<"\n\t.short\t"<<(unsigned)(unsigned short)s[k];
+ }
+ out<<"\n";
+ }else if( t->type==CG_BINFILE ){
+ string file=tostring(t->string_value);
+ ifstream is( file.c_str() );
+ if( !is.good() ) fail( "Unable to read from file '%s'",file.c_str() );
+ for(;;){
+ char buf[16];
+ is.read( buf,16 );
+ int n=is.gcount();
+ if( !n ) break;
+ out<<"\t.byte\t";
+ for( int k=0;k<n;++k ){
+ if( k ) out<<',';
+ out<<(unsigned)(unsigned char)buf[k];
+ }
+ out<<'\n';
+ }
+ is.close();
+ }else if( t->type==CG_LABEL ){
+ out<<tostring(t->string_value)<<":\n";
+ }else{
+ assert(0);
+ }
+ }else if( CGSym *t=e->sym() ){
+ out<<"\t.long\t"<<t->value<<'\n';
+ }else if( CGLea *t=e->lea() ){
+ CGMem *m=t->exp->mem();
+ assert(m);
+ if( m->flags==1 ){ //PARAM
+ }else if( m->flags==2 ){ //LOCAL
+ out<<"\t.long\t"<<m->offset<<'\n';
+ }else if( CGSym *t=m->exp->sym() ){
+ assert(t);
+ if( m->offset ){
+ out<<"\t.long\t"<<t->value<<'+'<<m->offset<<'\n';
+ }else{
+ out<<"\t.long\t"<<t->value<<'\n';
+ }
+ }else{
+ assert(0);
+ }
+ }else{
+ cout<<e<<endl;
+ assert(0);
+ }
+ }
+}
+
+void CGModule_PPC::emitFooter(){
+ //emit fp_const
+ if( fp_const ){
+ setSeg( "data" );
+ out<<fp_const->value<<":\n";
+ out<<"\t.double\t0r4.50360177485414400000e15\n";
+ }
+}
--- /dev/null
+
+#ifndef CGMODULE_PPC_H
+#define CGMODULE_PPC_H
+
+#include "cgmodule.h"
+#include "cgframe_ppc.h"
+
+struct CGModule_PPC : public CGModule{
+ string seg;
+ CGSym* fp_const;
+
+ CGModule_PPC( std::ostream &out );
+
+ void setSeg( string t );
+
+ CGFrame* frame( CGFun *fun );
+ void emitHeader();
+ void emitImport( string t );
+ void emitExport( string t );
+ void emitFrame( CGFrame *f );
+ void emitData( CGDat *d );
+ void emitFooter();
+};
+
+#endif
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgmodule_x86.h"
+#include "cgfixfp_x86.h"
+
+static bool USE_NASM=false; //NASM doesn't seem to work at all
+
+CGModule_X86::CGModule_X86( ostream &o ):CGModule(o){
+}
+
+void CGModule_X86::setSeg( string t ){
+ if( seg==t ) return;
+ seg=t;
+ if( USE_NASM ){
+ out<<"\tsection\t."<<seg<<'\n';
+ }else{
+ out<<"\tsection\t"<<seg<<'\n';
+ }
+}
+
+CGFrame *CGModule_X86::frame( CGFun *fun ){
+ return new CGFrame_X86( fun,this );
+}
+
+void CGModule_X86::emitHeader(){
+ if( env_platform=="win32" ){
+ out<<"\tformat\tMS COFF\n";
+ }else if( env_platform=="linux" ){
+ out<<"\tformat\tELF\n";
+ }else if( env_platform!="macos" ){
+ assert(0);
+ }
+}
+
+void CGModule_X86::emitImport( string t ){
+ if( USE_NASM ){
+ out<<"\textern\t"<<t<<'\n';
+ }else{
+ out<<"\textrn\t"<<t<<'\n';
+ }
+}
+
+void CGModule_X86::emitExport( string t ){
+ if( USE_NASM ){
+ out<<"\tglobal\t"<<t<<'\n';
+ }else{
+ out<<"\tpublic\t"<<t<<'\n';
+ }
+}
+
+void CGModule_X86::emitFrame( CGFrame *f ){
+
+ if( env_platform=="win32" ){
+ setSeg( "\"code\" code" );
+ }else if( env_platform=="linux" ){
+ setSeg( "\"code\" executable" );
+ }else if( env_platform=="macos" ){
+ setSeg( "text" );
+ }
+
+ if( env_platform=="macos" ){
+ emitMacFrame( f );
+ return;
+ }
+
+ CGFrame_X86 *frame=dynamic_cast<CGFrame_X86*>(f);
+ assert( frame );
+
+ int k,n_use[7]={0};
+
+ for( k=0;k<frame->regs.size();++k ){
+ CGReg *r=frame->regs[k];
+ if( r->isint() && r->id>=14 && r->color>=0 && r->color<7 ) ++n_use[r->color];
+ }
+
+ if( frame->extern_jsrs ){
+ n_use[3]=n_use[4]=n_use[5]=-1;
+ }
+
+ int local_sz=frame->local_sz;
+
+ //create frame
+ out<<frame->fun->sym->value<<":\n";
+
+ out<<"\tpush\tebp\n";
+ out<<"\tmov\tebp,esp\n";
+ emitSubEsp( local_sz );
+ //push callee save
+ if( n_use[3] ) out<<"\tpush\tebx\n";
+ if( n_use[4] ) out<<"\tpush\tesi\n";
+ if( n_use[5] ) out<<"\tpush\tedi\n";
+
+ CGAsm *as;
+
+ for( as=frame->assem.begin;as!=frame->assem.end;as=as->succ ){
+ if( as->stm && as->stm->ret() ){
+ //pop callee save
+ if( n_use[5] ) out<<"\tpop\tedi\n";
+ if( n_use[4] ) out<<"\tpop\tesi\n";
+ if( n_use[3] ) out<<"\tpop\tebx\n";
+ out<<"\tmov\tesp,ebp\n";
+ out<<"\tpop\tebp\n";
+ }
+
+ const char *p=as->assem;
+ if( !p ) continue;
+
+ out<<p;
+ }
+}
+
+void CGModule_X86::emitSubEsp( int sz ){
+ while( sz>4096 ){
+ out<<"\tsub\tesp,4092\n\tpush\teax\n";
+ sz-=4096;
+ }
+ if( sz ) out<<"\tsub\tesp,"<<sz<<'\n';
+}
+
+void CGModule_X86::emitMacFrame( CGFrame *f ){
+
+ CGFrame_X86 *frame=dynamic_cast<CGFrame_X86*>(f);
+ assert( frame );
+
+ int k,n_use[7]={0};
+
+ for( k=0;k<frame->regs.size();++k ){
+ CGReg *r=frame->regs[k];
+ if( r->isint() && r->id>=14 && r->color>=0 && r->color<7 ) ++n_use[r->color];
+ }
+
+ int save_sz=8; //ret address+ebp
+ if( n_use[3] ) save_sz+=4; //ebx
+ if( n_use[4] ) save_sz+=4; //esi
+ if( n_use[5] ) save_sz+=4; //edi
+
+ int local_sz=frame->local_sz;
+ int param_sz=frame->param_sz;
+
+ int frame_sz=param_sz+local_sz+save_sz;
+
+ frame_sz=(frame_sz+15)&~15;
+
+ param_sz=frame_sz-(local_sz+save_sz);
+
+ //create frame
+ out<<frame->fun->sym->value<<":\n";
+
+ //push ebp
+ out<<"\tpush\tebp\n";
+ out<<"\tmov\tebp,esp\n";
+
+ if( save_sz>8 ){
+ emitSubEsp( local_sz );
+ if( n_use[3] ) out<<"\tpush\tebx\n";
+ if( n_use[4] ) out<<"\tpush\tesi\n";
+ if( n_use[5] ) out<<"\tpush\tedi\n";
+ emitSubEsp( param_sz );
+ }else{
+ emitSubEsp( local_sz+param_sz );
+ }
+
+ CGAsm *as;
+
+ for( as=frame->assem.begin;as!=frame->assem.end;as=as->succ ){
+ if( as->stm && as->stm->ret() ){
+ //pop callee save
+ if( save_sz>8 ){
+ if( param_sz ) out<<"\tadd\tesp,"<<param_sz<<'\n';
+ if( n_use[5] ) out<<"\tpop\tedi\n";
+ if( n_use[4] ) out<<"\tpop\tesi\n";
+ if( n_use[3] ) out<<"\tpop\tebx\n";
+ }
+ out<<"\tmov\tesp,ebp\n";
+ out<<"\tpop\tebp\n";
+ }
+
+ const char *p=as->assem;
+ if( !p ) continue;
+
+ out<<p;
+ }
+}
+
+void CGModule_X86::emitData( CGDat *d ){
+
+ if( env_platform=="win32" ){
+ setSeg( "\"data\" data writeable align 8" );
+ }else if( env_platform=="linux" ){
+ setSeg( "\"data\" writeable align 8" );
+ }else if( env_platform=="macos" ){
+ setSeg( "data" );
+ }
+
+ int align=4;
+ if( d->exps.size()==1 ){
+ switch( d->exps[0]->type ){
+ case CG_INT8:
+ case CG_CSTRING:
+ align=1;
+ break;
+ case CG_INT16:
+ align=2;
+ break;
+ case CG_INT64:case CG_FLOAT64:
+ align=8;
+ break;
+ }
+ }
+ if( align!=1 ){
+ out<<"\talign\t"<<align<<"\n";
+ }
+
+ out<<d->value<<":\n";
+
+ for( int k=0;k<d->exps.size();++k ){
+
+ CGExp *e=d->exps[k];
+
+ if( CGLit *t=e->lit() ){
+ if( t->type==CG_INT8 ){
+ out<<"\tdb\t"<<unsigned(t->int_value)<<'\n';
+ }else if( t->type==CG_INT16 ){
+ out<<"\tdw\t"<<unsigned(t->int_value)<<'\n';
+ }else if( t->type==CG_INT32 ){
+ out<<"\tdd\t"<<int(t->int_value)<<'\n';
+ }else if( t->type==CG_INT64 ){
+ out<<"\tdd\t"<<int(t->int_value)<<','<<int(t->int_value>>int64(32))<<'\n';
+ }else if( t->type==CG_FLOAT32 ){
+ float f=t->float_value;
+ int n=*(int*)&f;
+ out<<"\tdd\t0x"<<hex<<n<<dec<<'\n';
+// float f=t->float_value;
+// out<<"\tdd\t0x"<<hex<<*((int*)&f)<<dec<<'\n';
+ }else if( t->type==CG_FLOAT64 ){
+ double f=t->float_value;
+ int64 n=*(int64*)&f;
+ out<<"\tdd\t0x"<<hex<<int(n)<<",0x"<<int(n>>int64(32))<<dec<<'\n';
+// double f=t->float_value;
+//#if __APPLE__ && __BIG_ENDIAN__
+// out<<"\tdd\t0x"<<hex<<*((int*)&f+1)<<",0x"<<*((int*)&f)<<dec<<'\n';
+//#else
+// out<<"\tdd\t0x"<<hex<<*((int*)&f)<<",0x"<<*((int*)&f+1)<<dec<<'\n';
+//#endif
+ }else if( t->type==CG_CSTRING ){
+ bstring s=t->string_value;
+ out<<"\tdb\t\"";
+ for( int k=0;k<s.size();++k ){
+ if( s[k]==34 ){
+ if( env_platform=="macos" ){
+ out<<"\\\"";
+ }else{
+ out<<"\",34,\"";
+ }
+ }else{
+ out<<(char)s[k];
+ }
+ }
+ out<<"\",0\n";
+ }else if( t->type==CG_BSTRING ){
+ bstring s=t->string_value;
+ out<<"\tdd\t"<<s.size();
+ for( int k=0;k<s.size();++k ){
+ if( k%16 ) out<<','<<(unsigned)s[k];
+ else out<<"\n\tdw\t"<<(unsigned)s[k];
+ }
+ out<<"\n";
+ }else if( t->type==CG_BINFILE ){
+ string file=tostring(t->string_value);
+ out<<"\tfile\t\""+file+"\"\n";
+ }else if( t->type==CG_LABEL ){
+ out<<tostring(t->string_value)<<":\n";
+ }else{
+ assert(0);
+ }
+ }else if( CGSym *t=e->sym() ){
+ out<<"\tdd\t"<<t->value<<'\n';
+ }else if( CGLea *t=e->lea() ){
+ CGMem *m=t->exp->mem();
+ assert(m);
+ if( CGReg *t=m->exp->reg() ){
+ out<<"\tdd\t"<<m->offset<<'\n';
+ }else if( CGSym *t=m->exp->sym() ){
+ assert(t);
+ if( m->offset ){
+ out<<"\tdd\t"<<t->value<<'+'<<m->offset<<'\n';
+ }else{
+ out<<"\tdd\t"<<t->value<<'\n';
+ }
+ }else{
+ assert(0);
+ }
+ }else{
+ fail( "cgmodule_x86::emitData - unrecognized data format" );
+ }
+ }
+}
+
+void CGModule_X86::emitFooter(){
+}
--- /dev/null
+
+#ifndef CGMODULE_X86_H
+#define CGMODULE_X86_H
+
+#include "cgmodule.h"
+#include "cgframe_x86.h"
+
+struct CGModule_X86 : public CGModule{
+ string seg;
+
+ CGModule_X86( ostream &out );
+
+ void setSeg( string t );
+
+ CGFrame* frame( CGFun *fun );
+ void emitHeader();
+ void emitImport( string t );
+ void emitExport( string t );
+ void emitFrame( CGFrame *f );
+ void emitMacFrame( CGFrame *f );
+ void emitData( CGDat *d );
+ void emitFooter();
+ void emitSubEsp( int sz );
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "../compiler/stdutil.h"
--- /dev/null
+
+#include "cgstd.h"
+
+#include "cgutil.h"
+
+static string _id(){
+ char buf[32];
+ static int n_id;
+ sprintf( buf,"_%i",++n_id );
+ return buf;
+}
+
+CGNop *CG::nop(){
+ return new CGNop;
+}
+
+CGXop *CG::xop( int op,CGReg *r,CGExp *exp ){
+ CGXop *t=new CGXop;
+ t->op=op;t->def=r;t->exp=exp;
+ return t;
+}
+
+CGRem *CG::rem( string comment ){
+ CGRem *t=new CGRem;
+ t->comment=comment;
+ return t;
+}
+
+CGAti *CG::ati( CGMem *mem ){
+ CGAti *t=new CGAti;
+ t->mem=mem;
+ return t;
+}
+
+CGAtd *CG::atd( CGMem *mem,CGSym *sym ){
+ CGAtd *t=new CGAtd;
+ t->mem=mem;t->sym=sym;
+ return t;
+}
+
+CGMov *CG::mov( CGExp *lhs,CGExp *rhs ){
+ CGMov *t=new CGMov;
+ t->lhs=lhs;t->rhs=rhs;
+ return t;
+}
+
+CGLab *CG::lab( CGSym *sym ){
+ CGLab *t=new CGLab;
+ t->sym=sym ? sym : CG::sym();
+ return t;
+}
+
+CGBra *CG::bra( CGSym *sym ){
+ CGBra *t=new CGBra;
+ t->sym=sym;
+ return t;
+}
+
+CGBcc *CG::bcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ){
+ CGBcc *t=new CGBcc;
+ t->cc=cc;t->lhs=lhs;t->rhs=rhs;t->sym=sym;
+ return t;
+}
+
+CGRet *CG::ret( CGExp *exp ){
+ CGRet *t=new CGRet;
+ t->exp=exp;
+ return t;
+}
+
+CGEva *CG::eva( CGExp *exp ){
+ CGEva *t=new CGEva;
+ t->exp=exp;
+ return t;
+}
+
+CGSeq *CG::seq( const std::vector<CGStm*> &stms ){
+ CGSeq *t=new CGSeq;
+ t->stms=stms;
+ return t;
+}
+
+CGSeq *CG::seq( CGStm *stm0,... ){
+ CGSeq *t=new CGSeq;
+ if( !stm0 ) return t;
+ t->stms.push_back( stm0 );
+ va_list args;
+ va_start( args,stm0 );
+ while( CGStm *p=va_arg(args,CGStm*) ) t->stms.push_back(p);
+ return t;
+}
+
+CGMem *CG::mem( int type,CGExp *exp,int offset ){
+ CGMem *t=new CGMem;
+ t->type=type;t->exp=exp;t->offset=offset;t->flags=0;
+ return t;
+}
+
+CGLea *CG::lea( CGExp *exp ){
+ CGLea *t=new CGLea;
+ t->type=CG_INT32;t->exp=exp;
+ return t;
+}
+
+CGCvt *CG::cvt( int type,CGExp *exp ){
+ CGCvt *t=new CGCvt;
+ t->type=type;t->exp=exp;
+ return t;
+}
+
+CGUop *CG::uop( int op,CGExp *exp ){
+ CGUop *t=new CGUop;
+ t->type=exp->type;t->op=op;t->exp=exp;
+ return t;
+}
+
+CGBop *CG::bop( int op,CGExp *lhs,CGExp *rhs ){
+ CGBop *t=new CGBop;
+ t->type=lhs->type;t->op=op;t->lhs=lhs;t->rhs=rhs;
+ return t;
+}
+
+CGJsr *CG::jsr( int type,int call_conv,CGExp *exp,const vector<CGExp*> &args ){
+ CGJsr *t=new CGJsr;
+ t->type=type;t->call_conv=call_conv;t->exp=exp;t->args=args;
+ return t;
+}
+
+CGJsr *CG::jsr( int type,int call_conv,CGExp *exp,CGExp *a0,CGExp *a1,CGExp *a2,CGExp *a3 ){
+ vector<CGExp*> args;
+ if( a0 ) args.push_back(a0);
+ if( a1 ) args.push_back(a1);
+ if( a2 ) args.push_back(a2);
+ if( a3 ) args.push_back(a3);
+ return jsr( type,call_conv,exp,args );
+}
+
+CGJsr *CG::jsr( int type,string t_sym,const vector<CGExp*> &args ){
+ return jsr( type,CG_CDECL,sym(t_sym,CG_IMPORT),args );
+}
+
+CGJsr *CG::jsr( int type,string t_sym,CGExp *a0,CGExp *a1,CGExp *a2,CGExp *a3 ){
+ vector<CGExp*> args;
+ if( a0 ) args.push_back(a0);
+ if( a1 ) args.push_back(a1);
+ if( a2 ) args.push_back(a2);
+ if( a3 ) args.push_back(a3);
+ return jsr( type,t_sym,args );
+}
+
+CGVfn *CG::vfn( CGExp *exp,CGExp *self ){
+ CGVfn *t=new CGVfn;
+ t->type=exp->type;t->exp=exp;t->self=self;
+ return t;
+}
+
+CGScc *CG::scc( int cc,CGExp *lhs,CGExp *rhs ){
+ CGScc *t=new CGScc;
+ t->type=CG_INT32;t->cc=cc;t->lhs=lhs;t->rhs=rhs;
+ return t;
+}
+
+CGEsq *CG::esq( CGStm *lhs,CGExp *rhs ){
+ CGEsq *t=new CGEsq;
+ t->type=rhs->type;t->lhs=lhs;t->rhs=rhs;
+ return t;
+}
+
+CGFrm *CG::frm(){
+ CGFrm *t=new CGFrm;
+ t->type=CG_PTR;
+ return t;
+}
+
+CGLit *CG::lit( int val ){
+ CGLit *t=new CGLit;
+ t->type=CG_INT32;t->int_value=val;
+ return t;
+}
+
+CGLit *CG::lit( int64 val ){
+ CGLit *t=new CGLit;
+ t->type=CG_INT64;t->int_value=val;
+ return t;
+}
+
+CGLit *CG::lit( float val ){
+ CGLit *t=new CGLit;
+ t->type=CG_FLOAT32;t->float_value=val;
+ return t;
+}
+
+CGLit *CG::lit( double val ){
+ CGLit *t=new CGLit;
+ t->type=CG_FLOAT64;t->float_value=val;
+ return t;
+}
+
+CGLit *CG::lit( bstring val,int type ){
+ CGLit *t=new CGLit;
+ t->type=type;t->string_value=val;
+ return t;
+}
+
+CGTmp *CG::tmp( int type,string id ){
+ CGTmp *t=new CGTmp;
+ t->type=type;t->ident=id.size() ? id : _id();t->owner=0;
+ return t;
+}
+
+CGSym *CG::sym(){
+ CGSym *t=new CGSym;
+ t->type=CG_INT32;
+ t->value=_id();
+ t->linkage=CG_INTERNAL;
+ return t;
+}
+
+CGSym *CG::sym( string id,int linkage ){
+ CGSym *t=new CGSym;
+ t->type=CG_INT32;
+ t->value=id;
+ t->linkage=linkage;
+ return t;
+}
+
+CGDat *CG::dat(){
+ CGDat *t=new CGDat;
+ t->type=CG_INT32;
+ t->value=_id();
+ t->linkage=CG_INTERNAL;
+ return t;
+}
+
+CGDat *CG::dat( string id ){
+ CGDat *t=new CGDat;
+ t->type=CG_INT32;
+ t->value=id;
+ t->linkage=CG_EXPORT;
+ return t;
+}
+
+CGFun *CG::fun( int type,int call_conv,CGSym *sym,CGExp *self ){
+ CGFun *t=new CGFun;
+ t->type=type;t->call_conv=call_conv;t->sym=sym;t->self=self;
+ return t;
+}
+
+CGFun *CG::visitFun( CGFun *fun,CGVisitor &vis ){
+
+ int k;
+ CGFun *out=0;
+ bool copy=false;
+ vector<CGExp*> args;
+
+ CGSym *sym=fun->sym->visit( vis )->sym();
+ CGExp *self=fun->self ? fun->self->visit( vis ) : 0;
+ if( sym!=fun->sym || self!=fun->self ) copy=true;
+
+ for( k=0;k<fun->args.size();++k ){
+ args.push_back( fun->args[k]->visit( vis ) );
+ if( args.back()!=fun->args[k] ) copy=true;
+ }
+
+ CGStm *stm=0;
+
+ for( k=0;;++k ){
+
+ if( copy ){
+ out=CG::fun( fun->type,fun->call_conv,sym,self );
+ out->args=args;
+ out->stms.reserve( fun->stms.size() );
+ for( int j=0;j<k;++j ) out->stms.push_back( fun->stms[j] );
+ if( stm ) out->stms[out->stms.size()-1]=stm;
+ copy=false;
+ }
+
+ if( k==fun->stms.size() ) break;
+
+ stm=fun->stms[k]->visit( vis );
+
+ if( out ){
+ out->stms.push_back( stm );
+ }else{
+ if( stm!=fun->stms[k] ) copy=true;
+ }
+ }
+
+ return out ? out : fun;
+}
+
+int CG::swapcc( int cg_cc ){
+ switch( cg_cc ){
+ case CG_EQ:return CG_NE;
+ case CG_NE:return CG_EQ;
+ case CG_LT:return CG_GE;
+ case CG_GT:return CG_LE;
+ case CG_LE:return CG_GT;
+ case CG_GE:return CG_LT;
+ case CG_LTU:return CG_GEU;
+ case CG_GTU:return CG_LEU;
+ case CG_LEU:return CG_GTU;
+ case CG_GEU:return CG_LTU;
+ }
+ assert(0);
+ return 0;
+}
+
+CGLit *CG::lit0=CG::lit(0);
+CGLit *CG::lit1=CG::lit(1);
--- /dev/null
+
+#ifndef CGUTIL_H
+#define CGUTIL_H
+
+#include "cgcode.h"
+
+namespace CG{
+ CGNop* nop();
+ CGXop* xop( int op,CGReg *def,CGExp *exp );
+ CGRem* rem( string comment );
+ CGAti* ati( CGMem *mem );
+ CGAtd* atd( CGMem *mem,CGSym *sym );
+ CGMov* mov( CGExp *lhs,CGExp *rhs );
+ CGLab* lab( CGSym *sym=0 );
+ CGBra* bra( CGSym *sym );
+ CGBcc* bcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym );
+ CGRet* ret( CGExp *exp );
+ CGEva* eva( CGExp *exp );
+ CGSeq* seq( const std::vector<CGStm*> &stms );
+ CGSeq* seq( CGStm *stm0,... );
+
+ CGCvt* cvt( int type,CGExp *exp );
+ CGMem* mem( int type,CGExp *exp,int offset=0 );
+ CGUop* uop( int op,CGExp *exp );
+ CGBop* bop( int op,CGExp *lhs,CGExp *rhs );
+ CGScc* scc( int cc,CGExp *lhs,CGExp *rhs );
+ CGJsr* jsr( int type,int call_conv,CGExp *exp,const std::vector<CGExp*> &args );
+ CGJsr* jsr( int type,int call_conv,CGExp *exp,CGExp *a0=0,CGExp *a1=0,CGExp *a2=0,CGExp *a3=0 );
+ CGJsr* jsr( int type,string exp,const std::vector<CGExp*> &args );
+ CGJsr* jsr( int type,string exp,CGExp *a0=0,CGExp *a1=0,CGExp *a2=0,CGExp *a3=0 );
+ CGVfn* vfn( CGExp *exp,CGExp *self );
+ CGEsq* esq( CGStm *lhs,CGExp *rhs );
+ CGLea* lea( CGExp *exp );
+
+ CGLit* lit( int val );
+ CGLit* lit( int64 val );
+ CGLit* lit( float val );
+ CGLit* lit( double val );
+ CGLit* lit( bstring val,int type=CG_BSTRING );
+
+ CGFrm* frm();
+ CGSym* sym();
+ CGSym* sym( string ident,int linkage );
+ CGDat* dat();
+ CGDat* dat( string ident );
+ CGTmp* tmp( int type,string ident="" );
+
+ CGFun* fun( int type,int call_conv,CGSym *sym,CGExp *self );
+
+ CGFun* visitFun( CGFun *fun,CGVisitor &vis );
+
+ int swapcc( int cg_cc );
+
+ extern CGLit *lit0,*lit1;
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "cgstd.h"
+
+#include "codegen.h"
+#include "cgdebug.h"
+#include "cgallocregs.h"
+
+#include "cgmodule_x86.h"
+#include "cgmodule_ppc.h"
+
+void cgGenCode( ostream &o,const vector<CGFun*> &funs ){
+
+ CGModule *mod;
+
+ if( opt_arch=="x86" ) mod=new CGModule_X86(o);
+ else if( opt_arch=="ppc" ) mod=new CGModule_PPC(o);
+ else fail( "No backend available" );
+
+ for( int k=0;k<funs.size();++k ){
+
+ CGFun *fun=funs[k];
+
+// cout<<"Fun:"<<fun->sym->value<<endl;
+
+ CGFrame *frame=mod->createFrame( fun );
+
+// cout<<frame->fun;
+
+// cout<<"FindEscapes"<<endl;
+ frame->findEscapes(); //local escaping tmps
+
+ //cout<<"RenameTmps"<<endl;
+ frame->renameTmps(); //rename tmps->regs
+
+ //cout<<"Linearize"<<endl;
+ frame->linearize(); //remove SEQ and ESQ nodes
+
+ //cout<<"fixInt64"<<endl;
+ frame->fixInt64(); //rewrite int_64 code
+
+ //cout<<"fixSymbols"<<endl;
+ frame->fixSymbols(); //fix symbols depending on platform
+
+ //cout<<"preOptimize"<<endl;
+ frame->preOptimize(); //do some opts before asm gen
+
+ //cout<<"genAssem"<<endl;
+ frame->genAssem();
+
+ //cout<<"createFlow"<<endl;
+ frame->createFlow();
+
+// cout<<frame->assem;
+
+ //cout<<"optDeadCode"<<endl;
+ frame->optDeadCode();
+
+ //cout<<"optDupLoads"<<endl;
+ frame->optDupLoads();
+
+// cout<<frame->fun;
+// cout<<frame->assem;
+
+ //cout<<"allocRegs"<<endl;
+ frame->allocRegs();
+
+ frame->finish();
+
+ frame->deleteFlow();
+
+// frame->peepOpt(); //BROKEN!!!!!
+
+ //cout<<frame->assem;
+ }
+
+ mod->emitModule();
+}
--- /dev/null
+
+#ifndef CODEGEN_H
+#define CODEGEN_H
+
+#include "cgcode.h"
+#include "cgutil.h"
+
+void cgGenCode( ostream &o,const vector<CGFun*> &funcs );
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "std.h"
+#include "parser.h"
+#include "output.h"
+#include "config.h"
+
+using namespace CG;
+
+int main( int argc,char *argv[] ){
+
+ stdutil_init( argc,argv );
+
+ int demo_days=demoDays();
+
+ if( !opt_infile.size() ){
+ if( demo_days<0 ){
+ cout<<"BlitzMax Release Version "<<BCC_VERSION<<endl;
+ }else if( demo_days<30 ){
+ cout<<"BlitzMax Demo Version "<<BCC_VERSION<<" ("<<(30-demo_days)<<(demo_days<29 ? " days" : " day")<<" remaining)"<<endl;
+ }else{
+ cout<<"BlitzMax Demo Version "<<BCC_VERSION<<" (expired)"<<endl;
+ }
+ exit(0);
+ }
+
+ if( demo_days>=30 ){
+ cout<<"BlitzMax demo has expired. Please visit www.blitzbasic.com to buy the full version of BlitzMax."<<endl;
+ exit(0);
+ }
+
+ if( !ftime(opt_infile) ) fail( "Input file not found" );
+
+ bool t_debug=opt_debug;
+
+ Parser parser;
+
+ if( opt_verbose ) cout<<"Parsing..."<<endl;
+ parser.parse();
+
+ if( opt_verbose ) cout<<"Resolving types..."<<endl;
+ Type::resolveTypes();
+
+ if( opt_verbose ) cout<<"Resolving decls..."<<endl;
+ Decl::resolveDecls();
+
+ if( opt_verbose ) cout<<"Resolving blocks..."<<endl;
+ Block::resolveBlocks();
+
+ if( opt_verbose ) cout<<"Evaluating fun blocks..."<<endl;
+ Block::evalFunBlocks();
+
+ opt_debug=t_debug;
+ opt_release=!opt_debug;
+
+ if( opt_verbose ) cout<<"Generating assembly..."<<endl;
+ FunBlock::genAssem();
+
+ if( opt_verbose ) cout<<"Generating interface..."<<endl;
+ FunBlock::genInterface();
+
+ return 0;
+}
--- /dev/null
+
+#include "std.h"
+#include "block.h"
+#include "stm.h"
+#include "toker.h"
+#include "output.h"
+
+using namespace CG;
+
+static vector<FunBlock*> _funBlocks;
+static vector<ClassBlock*> _classBlocks;
+
+//******************** Block **********************
+Block::Block( Block *o ):outer(o),cg_debug(0){
+ fun_block=outer ? outer->fun_block : 0;
+ cg_enter=CG::seq(0);
+ cg_leave=CG::seq(0);
+ debug_on=outer ? outer->debug_on : opt_debug;
+}
+
+CGDat *Block::debugScope(){
+
+ if( cg_debug ) return cg_debug;
+
+ int kind=0;
+ string name;
+ DeclSeq *scope=&decls;
+
+ if( FunBlock *fun=dynamic_cast<FunBlock*>(this) ){
+ kind=1;
+ name=fun->fun_decl ? fun->fun_decl->ident : stripall( opt_infile );
+ }else if( ClassBlock *clas=dynamic_cast<ClassBlock*>(this) ){
+ kind=2;
+ scope=&clas->type->decls;
+ name=clas->class_decl->ident;
+ string meta=clas->class_decl->meta;
+ if( meta.size() ) name+="{"+meta+"}";
+ }else{
+ kind=3;
+ }
+
+ CGDat *d=CG::dat();
+
+ d->push_back( lit(kind) ); //kind
+ if( name.size() ) d->push_back( genCString(name) ); //name
+ else d->push_back( lit0 );
+
+ if( FunBlock *fun=dynamic_cast<FunBlock*>(this) ){
+ ClassBlock *clas=dynamic_cast<ClassBlock*>(outer);
+ if( clas && fun->type->method() ){
+ assert( fun->fun_scope->cg_exp->tmp() );
+ d->push_back( CG::lit(2) );
+ d->push_back( genCString("Self") );
+ d->push_back( genCString(":"+clas->class_decl->ident) );
+ d->push_back( lea(fun->fun_scope->cg_exp) );
+ }
+ }
+
+ for( int k=0;k<scope->size();++k ){
+ (*scope)[k]->debugDecl( d,kind );
+ }
+
+ d->push_back( lit0 );
+
+ return cg_debug=d;
+}
+
+void Block::emit( Stm *t ){
+ stms.push_back(t);
+}
+
+void Block::emit( CGStm *t ){
+ if( t ) fun_block->cg_fun->stms.push_back(t);
+}
+
+void Block::decl( Decl *d ){
+ decls.push_back(d);
+}
+
+void Block::declLocal( Decl *d ){
+ decls.push_back(d);
+ locals.push_back(d);
+}
+
+Val *Block::linearizeRef( Val *v ){
+ CGExp *e=v->cg_exp;
+
+ if( !e->sideEffects() ) return v;
+
+ while( CGEsq *t=e->esq() ){
+ emit( t->lhs );
+ e=t->rhs;
+ }
+
+ if( e->tmp() ) return new Val( v->type,e );
+
+ CGMem *t=e->mem();
+ if( !t ) fail( "Internal error: Can't linearize reference" );
+ CGTmp *p=tmp(CG_PTR);
+ emit( mov(p,t->exp) );
+ return new Val( v->type,mem(v->type->cgType(),p,t->offset) );
+}
+
+void Block::initRef( Val *lhs,Val *rhs ){
+ if( !lhs->type->refType() ) fail( "initRef expecting ref type" );
+
+ if( !lhs->cg_exp->tmp() && !lhs->cg_exp->mem() ){
+ cout<<lhs->cg_exp<<endl;
+ fail( "Internal error: Block::initRef - value is not a reference" );
+ }
+
+ if( lhs->refCounted() ){
+ rhs=rhs->retain();
+ }
+
+ emit( mov(lhs->cg_exp,rhs->cg_exp) );
+}
+
+void Block::assignRef( Val *lhs,Val *rhs ){
+
+ RefType *ref=lhs->type->refType();
+
+ if( !ref ) fail( "assignRef expecting ref type" );
+
+ if( !lhs->cg_exp->tmp() && !lhs->cg_exp->mem() ){
+ cout<<lhs->cg_exp<<endl;
+ fail( "Internal error: Block::assignRef - value is not a reference" );
+ }
+
+ if( !lhs->refCounted() ){
+ emit( mov( lhs->cg_exp,rhs->cg_exp ) );
+ return;
+ }
+
+ //Release LHS AFTER evaluating and incing RHS
+ CGTmp *t=tmp(CG_PTR);
+ emit( mov( t,rhs->retain()->cg_exp ) );
+ emit( lhs->release() );
+ emit( mov( lhs->cg_exp,t ) );
+}
+
+void Block::initGlobalRef( Val *lhs,Val *rhs ){
+ if( !lhs->type->refType() ) fail( "initGlobalRef expecting ref type" );
+ if( !lhs->cg_exp->mem() ) fail( "initGlobalRef expecting mem exp" );
+
+ if( lhs->refCounted() ){
+ rhs=rhs->retain();
+ }
+
+ static int init_bit;
+ static CGExp *init_var;
+
+ init_bit<<=1;
+ if( !init_bit ){
+ init_bit=1;
+ CGDat *d=dat();
+ d->push_back(lit0);
+ init_var=mem(CG_INT32,d);
+ }
+ CGLit *init_lit=lit(init_bit);
+
+ CGSym *t=sym();
+
+ emit( bcc(CG_NE,bop(CG_AND,init_var,init_lit),lit0,t) );
+ emit( mov(lhs->cg_exp,rhs->cg_exp) );
+ emit( mov(init_var,bop(CG_ORL,init_var,init_lit)) );
+ emit( lab(t) );
+}
+
+Val *Block::find( string id ){
+ Val *v;
+ Block *t;
+ for( t=this;t;t=t->outer ){
+ if( v=t->_find( id,this ) ) return v;
+ }
+ return findGlobal( id );
+}
+
+Val *Block::_find( string id,Block *from ){
+ Val *v=decls.find(id);
+ if( !v || !locals.find(id) ) return v;
+ return from && fun_block==from->fun_block ? v : 0;
+}
+
+void Block::eval(){
+ ClassBlock *clas=dynamic_cast<ClassBlock*>(this);
+
+ bool t_debug=opt_debug;
+ opt_debug=debug_on;
+
+ emit( cg_enter );
+ for( int k=0;k<stms.size();++k ){
+ Stm *st=stms[k];
+ source_info=st->source_info;
+ st->eval( this );
+ }
+ emit( cg_leave );
+
+ opt_debug=t_debug;
+
+ if( debug_on && !clas ){
+ if( strictMode || dynamic_cast<FunBlock*>(this) ){
+ cg_enter->push_back( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugEnterScope",CG_IMPORT),0),debugScope(),frm())) );
+ cg_leave->push_front( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugLeaveScope",CG_IMPORT),0))) );
+ }
+ }
+}
+
+void Block::resolveBlocks(){
+ int k;
+ for( k=0;k<_classBlocks.size();++k ) _classBlocks[k]->resolve();
+ for( k=0;k<_funBlocks.size();++k ) _funBlocks[k]->resolve();
+}
+
+void Block::evalFunBlocks(){
+ int k;
+ for( k=0;k<_funBlocks.size();++k ) _funBlocks[k]->eval();
+}
+
+void Block::evalClassBlocks(){
+ int k;
+ for( k=0;k<_classBlocks.size();++k ) _classBlocks[k]->eval();
+}
+
+//****************** Loop Block *******************
+LoopBlock::LoopBlock( Block *o,string lab ):Block(o),label(lab){
+ cont_sym=sym();
+ exit_sym=sym();
+ loop_sym=sym();
+}
+
+//**************** Function Block *****************
+FunBlock::FunBlock():Block(0),
+fun_decl(0),fun_scope(0),ret_tmp(0),ret_sym(0),data_ptr(0),data_stms(0){
+ fun_block=this;
+ sourceinfo=source_info;
+ _funBlocks.push_back( this );
+
+ type=new FunType( Type::int32,FunType::VOIDFUN );
+
+ string entry;
+
+ if( opt_apptype.size() ){
+ entry="_bb_main";
+ }else if( opt_module.size() && (moduleIdent(opt_module)==stripall(opt_infile)) ){
+ entry=mungModuleEntry( opt_module );
+ }else{
+ entry=mungObjectEntry( opt_infile );
+ }
+
+ CGSym *cg_sym=sym( entry,CG_EXPORT );
+
+ cg_fun=fun( CG_INT32,CG_CDECL,cg_sym,0 );
+}
+
+FunBlock::FunBlock( Block *o,string id,FunType *ty,bool pub,ExpSeq *defs ):Block(o),
+type(ty),cg_fun(0),fun_scope(0),ret_tmp(0),ret_sym(0),data_ptr(0),data_stms(0){
+ fun_block=this;
+ sourceinfo=source_info;
+ _funBlocks.push_back( this );
+
+ ClassBlock *class_blk=dynamic_cast<ClassBlock*>(outer);
+ ClassType *class_ty=class_blk ? class_blk->type : 0;
+
+ CGSym *cg_sym;
+
+ if( pub ){
+ if( class_blk ) cg_sym=sym( mungMember(class_blk->class_decl->ident,id),CG_EXPORT );
+ else cg_sym=sym( mungGlobal(id),CG_EXPORT );
+ }else{
+ cg_sym=sym();
+ }
+
+ fun_decl=new FunDecl(id,type,cg_sym,outer,defs);
+
+ if( class_ty ){
+ class_ty->methods.push_back(fun_decl);
+ }else if( outer ){
+ outer->decl(fun_decl);
+ if( pub ) publish( fun_decl );
+ }
+}
+
+void FunBlock::resolve(){
+ source_info=sourceinfo;
+
+ ClassBlock *class_blk=dynamic_cast<ClassBlock*>(outer);
+ ClassType *class_ty=class_blk ? class_blk->type : 0;
+
+ CGTmp *cg_self=0;
+
+ if( class_ty ){
+ if( type->method() ){
+ cg_self=tmp(CG_PTR);
+ Val *class_val=new Val(class_ty,class_blk->class_decl->val->cg_exp);
+ fun_scope=new Val( new ObjectType(class_val),cg_self );
+ }else{
+ fun_scope=class_blk->class_decl->val;
+ }
+ }
+
+ if( !cg_fun ){
+ //create cg_fun
+ CGSym *cg_sym=fun_decl->val->cg_exp->sym();
+ cg_fun=fun( type->return_type->cgType(),type->call_conv,cg_sym,cg_self );
+ for( int k=0;k<type->args.size();++k ){
+ cg_fun->args.push_back( tmp(type->args[k]->val->type->cgType()) );
+ }
+ }
+
+ //copy args to locals
+ for( int k=0;k<type->args.size();++k ){
+ Decl *d=type->args[k];
+ Type *ty=d->val->type;
+ CGExp *cg=cg_fun->args[k];
+ int attrs=0;
+ if( VarType *t=ty->varType() ){
+ ty=t->val_type;
+ cg=mem(ty->cgType(),cg,0);
+ }
+ Val *v=new Val( new RefType(ty,attrs),cg );
+ declLocal( new Decl(d->ident,v) );
+ }
+
+ ret_sym=sym();
+ ret_tmp=tmp( type->return_type->cgType() );
+
+ emit( new ReturnStm( (type->attrs&FunType::VOIDFUN) ? 0 : new NullExp() ) );
+}
+
+void FunBlock::eval(){
+
+ Block::eval();
+
+ //data statements?
+ if( data_ptr ){
+ data_stms->push_back( lit0 );
+ cg_enter->push_back( mov( mem(CG_PTR,data_ptr,0),data_stms ) );
+ }
+
+ //if main, prevent recursive startup
+ if( !outer ){
+ CGDat *d=dat();
+ d->push_back( lit0 );
+ CGMem *m=mem(CG_INT32,d);
+ CGSym *t=sym();
+ CGStm *s=seq(
+ bcc(CG_EQ,m,lit0,t),
+ ret(lit0),
+ lab(t),
+ mov(m,lit1),
+ 0 );
+ cg_enter->push_front(s);
+ }
+
+ cg_leave->push_front( lab(ret_sym) );
+ emit( ret(ret_tmp) );
+}
+
+Val *FunBlock::_find( string id,Block *from ){
+
+ Val *v;
+ if( v=Block::_find( id,from ) ) return v;
+ if( !fun_scope ) return 0;
+
+ //bit naughty! turn off debug for members of 'Self'
+ bool t_debug=debug_on;
+ debug_on=false;
+ v=fun_scope->find(id);
+ debug_on=t_debug;
+ return v;
+}
+
+void FunBlock::genAssem(){
+ vector<CGFun*> cgfuns;
+ int k;
+ for( k=0;k<_funBlocks.size();++k ) cgfuns.push_back( _funBlocks[k]->cg_fun );
+ string file=getdir(opt_infile)+"/.bmx/"+stripdir(opt_infile);
+ if( opt_apptype.size() ) file+="."+opt_apptype;
+ file+=config_mung+".s";
+ ofstream out(file.c_str());
+ cgGenCode( out,cgfuns );
+ out.close();
+}
+
+void FunBlock::genInterface(){
+ if( opt_apptype.size() ) return;
+ if( moduleIdent(opt_module)==stripall(opt_infile) ){
+ string file=modulePath(opt_module,true)+"/"+moduleIdent(opt_module)+config_mung+".i";
+ ofstream out(file.c_str());
+ int k;
+ for( k=0;k<moduleInfos.size();++k ) out<<"ModuleInfo \""<<moduleInfos[k]<<"\"\n";
+ for( k=0;k<moduleImports.size();++k ) out<<moduleImports[k]<<'\n';
+ out::operator<<( out,moduleExports );
+ out.close();
+ }else{
+ string file=getdir(opt_infile)+"/.bmx/"+stripdir(opt_infile)+config_mung+".i";
+ ofstream out(file.c_str());
+ for( int k=0;k<objectImports.size();++k ) out<<objectImports[k]<<'\n';
+ out::operator<<( out,objectExports );
+ out.close();
+ }
+}
+
+CGDat *FunBlock::dataPtr(){
+ if( data_ptr ) return data_ptr;
+
+ data_ptr=dat();
+ data_stms=dat();
+
+ data_ptr->push_back( lit0 );
+
+ return data_ptr;
+}
+
+CGDat *FunBlock::dataStms(){
+ dataPtr();
+ return data_stms;
+}
+
+//******************* Type Block ******************
+ClassBlock::ClassBlock( Block *o,string id,ClassType *ty ):Block(o),type(ty){
+ sourceinfo=source_info;
+ _classBlocks.push_back( this );
+
+ bool pub=(ty->attrs & ClassType::PRIVATE) ? false : true;
+
+ CGDat *d;
+ if( pub ) d=dat( mungGlobal(id) );
+ else d=dat();
+
+ class_decl=new Decl(id,type,d);
+
+ FunType *ctor_ty=new FunType( Type::int32,FunType::METHOD|FunType::VOIDFUN );
+ ctor=new FunBlock( this,"New",ctor_ty,true );
+ ctor_new=new Block( ctor );
+ field_ctors=new Block( ctor );
+ field_ctors->debug_on=false;
+ ctor->emit( new CtorStm( this,ctor_new ) );
+
+ dtor=0;
+ dtor_delete=0;
+
+ if( !opt_threaded ){
+ makeDtor();
+ }
+
+ outer->decl( class_decl );
+
+ if( pub ){
+ publish( class_decl );
+ }
+}
+
+void ClassBlock::makeDtor(){
+ if( !dtor ){
+ FunType *dtor_ty=new FunType( Type::int32,FunType::METHOD|FunType::VOIDFUN );
+ dtor=new FunBlock( this,"Delete",dtor_ty,true );
+ dtor->debug_on=false;
+
+ dtor_delete=new Block(dtor);
+ dtor->emit( new DtorStm( this,dtor_delete ) );
+ }
+}
+
+void ClassBlock::resolve(){
+ source_info=sourceinfo;
+
+ CGDat *vtbl=class_decl->val->cg_exp->dat();
+
+ Val *super_val=type->superVal();
+ CGExp *exts=super_val ? super_val->cg_exp : lit0;
+
+ //construct vtable methods
+ vector<ClassType*> stk;
+ for( ClassType *t=type;t;t=t->superClass() ) stk.push_back(t);
+
+ vector<Decl*> vtbl_methods;
+ for( ;stk.size();stk.pop_back() ){
+ ClassType *t=stk.back();
+ for( int k=0;k<t->methods.size();++k ){
+ Decl *d=t->methods[k];
+ string id=tolower(d->ident);
+
+ for( int j=0;j<vtbl_methods.size();++j ){
+ if( id!=tolower(vtbl_methods[j]->ident) ) continue;
+ vtbl_methods[j]=d;
+ d=0;break;
+ }
+ if( d ) vtbl_methods.push_back(d);
+ }
+ }
+
+ CGExp *db=debugScope();
+
+ vtbl->push_back( exts ); //super
+ vtbl->push_back( sym("bbObjectFree",CG_IMPORT) ); //free method!
+ vtbl->push_back( db ); //debug scope
+ vtbl->push_back( lit(type->sizeof_fields) ); //sizeof_fields
+ for( int k=0;k<vtbl_methods.size();++k ){ //methods
+ Val *v=vtbl_methods[k]->val;
+ vtbl->push_back( v->cg_exp );
+ if( v->type->funType()->attrs & FunType::ABSTRACT ){
+ if( type->attrs & ClassType::FINAL ){
+ fail( "Abstract method '%s' in final type '%s'",
+ vtbl_methods[k]->ident.c_str(),class_decl->ident.c_str() );
+ }
+ type->attrs|=ClassType::ABSTRACT;
+ }
+ }
+}
+
+void ClassBlock::eval(){
+ bool t_debug=opt_debug;
+ opt_debug=debug_on;
+ for( int k=0;k<stms.size();++k ){
+ Stm *st=stms[k];
+ source_info=st->source_info;
+ st->eval( this );
+ }
+ //globals initialized: register type
+ //CGDat *name=genCString(class_decl->ident);
+ CGDat *vtbl=class_decl->val->cg_exp->dat();
+
+ emit( eva( jsr( CG_INT32,"bbObjectRegisterType",vtbl ) ) );
+
+ opt_debug=t_debug;
+}
+
+void ClassBlock::decl( Decl *d ){
+ decls.push_back(d);
+ type->decls.push_back(d);
+}
--- /dev/null
+
+#ifndef BLOCK_H
+#define BLOCK_H
+
+#include "decl.h"
+
+struct Stm;
+struct Block;
+struct FunBlock;
+struct LabelStm;
+
+struct Block : public Scope{
+ Block *outer;
+ DeclSeq decls;
+ DeclSeq locals;
+ vector<Stm*> stms;
+ FunBlock *fun_block;
+ CGSeq *cg_enter,*cg_leave;
+ CGDat *cg_debug;
+ bool debug_on;
+
+ Block( Block *outer );
+
+ CGDat* debugScope();
+
+ void emit( Stm *t );
+ void emit( CGStm *t );
+ void declLocal( Decl *d );
+
+ Val* linearizeRef( Val *v );
+ void initRef( Val *lhs,Val *rhs );
+ void assignRef( Val *lhs,Val *rhs );
+ void initGlobalRef( Val *lhs,Val *rhs );
+
+ virtual void decl( Decl *d );
+
+ virtual Val* find( string id );
+ virtual Val* _find( string id,Block *from );
+
+ virtual void eval();
+
+ static void resolveBlocks();
+ static void evalFunBlocks();
+ static void evalClassBlocks();
+};
+
+struct LoopBlock : public Block{
+ CGSym *cont_sym,*exit_sym,*loop_sym;
+ string label;
+
+ LoopBlock( Block *outer,string lab );
+};
+
+struct FunBlock : public Block{
+ FunType* type;
+ Decl* fun_decl;
+ Val* fun_scope;
+
+ map<string,LabelStm*> labels;
+
+ CGDat* data_ptr;
+ CGDat* data_stms;
+
+ CGFun* cg_fun;
+ CGTmp* ret_tmp;
+ CGSym* ret_sym;
+
+ string sourceinfo;
+
+ FunBlock();
+ FunBlock( Block *outer,string id,FunType *ty,bool pub,ExpSeq *defs=0 );
+
+ virtual Val *_find( string id,Block *from );
+
+ void resolve();
+
+ virtual void eval();
+
+ CGTmp* gcTmp();
+
+ static void genAssem();
+ static void genInterface();
+
+ CGDat* dataPtr();
+ CGDat* dataStms();
+};
+
+struct ClassBlock : public Block{
+ ClassType *type;
+ Decl *class_decl;
+ FunBlock *ctor,*dtor;
+ Block *ctor_new;
+ Block *dtor_delete;
+ Block *field_ctors;
+
+ string sourceinfo;
+
+ ClassBlock( Block *outer,string id,ClassType *ty );
+
+ void makeDtor();
+
+ void resolve();
+
+ virtual void eval();
+
+ virtual void decl( Decl *d );
+};
+
+#endif
--- /dev/null
+
+#include "config.h"
+
+#include "std.h"
+
+#ifdef DEMO_VERSION
+
+#define BAD_DEMO 10000
+
+//#define DEMO_SECS_PER_DAY 1 //(60*60*24)
+#define DEMO_SECS_PER_DAY (60*60*24)
+
+#if _WIN32
+
+int demoDays(){
+
+ static const char *key_path="SOFTWARE\\Blitz Research\\BlitzMax\\CurrentVersion\\Setup";
+
+ HKEY key;
+ char name[32];
+ sprintf( name,"DriverKey%s",DEMO_VERSION );
+
+ string p=getenv( "COMSPEC" );
+ int i=p.rfind( '\\' );
+ if( i==string::npos ) return BAD_DEMO;
+
+ p=p.substr( 0,i )+"\\PROTOC0L.IN"+DEMO_VERSION;
+
+ if( RegOpenKeyEx( HKEY_LOCAL_MACHINE,key_path,0,KEY_READ|KEY_WRITE,&key )==ERROR_SUCCESS ){
+
+ if( FILE *f=fopen( p.c_str(),"rb" ) ){
+
+ char value[MAX_PATH];
+
+ fgets( value,MAX_PATH,f );
+ fclose( f );
+ string a=value;
+
+ DWORD type,size=MAX_PATH;
+ LONG res=RegQueryValueEx( key,name,0,&type,(unsigned char*)value,&size );
+ RegCloseKey( key );
+ string b=value;
+
+ if( res==ERROR_SUCCESS && a==b ){
+ int64 then=toint( string(value) );
+ double secs=difftime( time(0),time_t(then) );
+ if( secs>=0 ) return (int)(secs/DEMO_SECS_PER_DAY);
+ }
+ }
+
+ }else if( RegCreateKeyEx( HKEY_LOCAL_MACHINE,key_path,0,0,0,KEY_READ|KEY_WRITE,0,&key,0 )==ERROR_SUCCESS ){
+
+ if( FILE *f=fopen( p.c_str(),"rb" ) ){
+
+ fclose( f );
+
+ }else if( FILE *f=fopen( p.c_str(),"wb" ) ){
+
+ string t=fromint(int64(time(0)));
+
+ int r=fputs( t.c_str(),f );
+ fclose( f );
+
+ if( r>=0 ){
+ LONG r=RegSetValueEx( key,name,0,REG_SZ,(unsigned char*)t.c_str(),t.size()+1 );
+ RegCloseKey( key );
+ if( r==ERROR_SUCCESS ) return 0;
+ }
+ }
+
+ }
+ return BAD_DEMO;
+}
+
+#elif __APPLE__
+
+int demoDays(){
+
+ FILE *f;
+ FSRef fsref;
+ CFNumberRef num;
+ CFAbsoluteTime now,time1,time2;
+ char home[1024],as_dir[1024],sup_dir[1024],sup_file[1024],tmp[32];
+
+ sprintf( tmp,".version%s",DEMO_VERSION );
+
+ CFStringRef key=CFStringCreateWithCString( 0,tmp,kCFStringEncodingASCII );
+ CFStringRef app=CFStringCreateWithCString( 0,"com.brl.bmx",kCFStringEncodingASCII );
+
+ FSFindFolder( kUserDomain,kVolumeRootFolderType,false,&fsref );
+ FSRefMakePath( &fsref,(unsigned char *)home,1024 );
+
+ sprintf( as_dir,"%s/Library/Application Support",home );
+ sprintf( sup_dir,"%s/Library/Application Support/Blitz Research",home );
+ sprintf( sup_file,"%s/Library/Application Support/Blitz Research/%s",home,tmp );
+
+ time1=0;
+ if( num=(CFNumberRef)CFPreferencesCopyAppValue( key,app ) ){
+ if( !CFNumberGetValue( num,kCFNumberFloat64Type,&time1 ) ) time1=0;
+ }
+
+ time2=0;
+ if( f=fopen( sup_file,"rb") ){
+ if( fread( &time2,8,1,f) !=1 ) time2=0;
+ fclose(f);
+ }
+
+ now=CFAbsoluteTimeGetCurrent();
+
+ if( time1 && time2 ){
+ if( fabs(time1-time2)<1 ){
+ CFTimeInterval secs=now-time1;
+ if( secs>=0 ) return (int)(secs/DEMO_SECS_PER_DAY);
+ }
+ }else if( !time1 && !time2 ){
+ mkdir( as_dir,0777 );
+ mkdir( sup_dir,0777 );
+ if( f=fopen( sup_file,"wb" ) ){
+ if( fwrite( &now,8,1,f )==1 ){
+ fclose( f );
+ num=CFNumberCreate(0,kCFNumberFloat64Type,&now);
+ CFPreferencesSetAppValue( key,num,app );
+ if( CFPreferencesAppSynchronize( app ) ) return 0;
+ }
+ fclose( f );
+ }
+ }
+ return BAD_DEMO;
+}
+#endif
+
+#else
+
+int demoDays(){
+ return -1;
+}
+
+#endif
--- /dev/null
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+//compiler version
+#define BCC_VERSION "1.50"
+
+//identifier for demo - bump for fresh demo, disable for release
+//#define DEMO_VERSION "5"
+
+//days demo has been going, returns -1 for not a demo
+int demoDays();
+
+#endif
--- /dev/null
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+//compiler version
+#define BCC_VERSION "1.49"
+
+//identifier for demo - bump for fresh demo, disable for release
+//#define DEMO_VERSION "5"
+
+//days demo has been going, returns -1 for not a demo
+int demoDays();
+
+#endif
--- /dev/null
+
+#include "std.h"
+#include "decl.h"
+#include "exp.h"
+
+#include "../codegen/cgdebug.h"
+
+static vector<ConstDecl*> _constDecls;
+static vector<FunDecl*> _funDecls;
+
+//********************* Decl **********************
+Decl::Decl( string id,Val *v ):ident(id),val(v){
+}
+
+Decl::Decl( string id,Type *ty,CGExp *cg ):ident(id),val(new Val(ty,cg)){
+}
+
+void Decl::setMetaData( string meta ){
+ this->meta=meta;
+}
+
+string Decl::debugEncoding(){
+ Type *t=val->type;
+ string e=t->encoding();
+ if( e.size() && e[0]==':' && t->exObjectType() ) e='?'+e.substr(1);
+ if( meta.size() ){
+ e+="{"+meta+"}";
+ }
+ return e;
+}
+
+void Decl::resolveDecls(){
+ int k;
+ if( opt_verbose ) cout<<"Resolving const decls..."<<endl;
+ for( k=0;k<_constDecls.size();++k ) _constDecls[k]->resolve();
+ if( opt_verbose ) cout<<"Resolving fun decls..."<<endl;
+ for( k=0;k<_funDecls.size();++k ) _funDecls[k]->resolve();
+}
+
+void Decl::debugDecl( CGDat *d,int blockKind ){
+
+ CGExp *e=val->cg_exp;
+ if( !e ) return;
+
+ if( val->constant() ){
+ if( val->type->numericType() || val->type->stringType() ){
+ bstring t=val->stringValue();
+
+ d->push_back( CG::lit(1) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( genBBString2( t ) );
+
+ /*
+ CGDat *dt=CG::dat();
+ dt->push_back( CG::sym("bbStringClass",CG_IMPORT) );
+ dt->push_back( CG::lit(0x7ffffffe) ); //normally 0x7fffffff - 0x..fe indicates 'ignore for GC'.
+ dt->push_back( CG::lit(t,CG_BSTRING) );
+ d->push_back( dt );
+ */
+
+ /*
+ d->push_back( CG::lit(1) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( val->cast(Type::stringObject)->cg_exp );
+ */
+
+ return;
+ }
+ }
+
+ if( !val->type->refType() ){
+ if( blockKind==2 && val->type->funType() ){
+ //type method/function
+ int dt=7;
+ if( CGVfn *t=e->vfn() ){
+ e=t->exp;
+ dt=6;
+ }
+ if( CGMem *t=e->mem() ){
+ d->push_back( CG::lit( dt ) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( CG::lit( t->offset ) );
+ }else if( CGSym *t=e->sym() ){
+ d->push_back( CG::lit( dt ) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( t );
+ }
+ }
+ return;
+ }
+
+ if( CGTmp *t=e->tmp() ){
+ d->push_back( CG::lit(2) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( CG::lea(t) );
+ return;
+ }
+
+ if( CGMem *t=e->mem() ){
+ if( t->exp->tmp() ){
+ if( blockKind==2 ){
+ //field
+ d->push_back( CG::lit(3) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( CG::lit(t->offset) );
+ }else{
+ d->push_back( CG::lit(5) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( CG::lea(t->exp->tmp()) );
+ }
+ return;
+ }else if( t->exp->sym() && !t->offset ){
+ d->push_back( CG::lit(4) );
+ d->push_back( genCString(ident) );
+ d->push_back( genCString(debugEncoding()) );
+ d->push_back( t->exp );
+ return;
+ }
+ }
+ return;
+}
+
+//***************** fun Decl ********************
+FunDecl::FunDecl( string id,FunType *ty,CGExp *cg,Scope *sc,ExpSeq *defs ):Decl( id,ty,cg ),scope(sc),defaults(defs){
+ sourceinfo=source_info;
+ _funDecls.push_back( this );
+}
+
+void FunDecl::resolve(){
+
+ source_info=sourceinfo;
+ FunType *fun=val->type->funType();
+
+ ClassBlock *class_block=dynamic_cast<ClassBlock*>(scope);
+
+ if( class_block ){
+ if( Val *v=class_block->type->findSuperMethod( ident ) ){
+ FunType *t=v->type->funType();
+ if( t->attrs & FunType::FINAL ){
+ fail( "Final methods cannot be overridden" );
+ }
+ if( !fun->extends(t) ){
+ fail( "Overriding method differs by type" );
+ }
+ }
+ }
+
+ if( defaults ){
+ int k;
+ for( k=0;k<defaults->size();++k ){
+ Exp *e=(*defaults)[k];
+ if( !e ) continue;
+ Val *v=e->eval(scope,fun->args[k]->val->type);
+ if( !v->constant() ) fail( "Function defaults must be constant" );
+ fun->args[k]->val->cg_exp=v->cg_exp;
+ }
+ }
+ if( !val->cg_exp ){
+ string id=ident;
+ if( fun->call_conv==CG_STDCALL ){
+ int sz=0;
+ for( int k=0;k<fun->args.size();++k ){
+ int n=fun->args[k]->val->type->size();
+ sz+=n>4 ? n : 4;
+ }
+ id+="@"+fromint(sz);
+ }
+ val->cg_exp=CG::sym( id,CG_IMPORT );
+ }
+}
+
+//****************** ConstDecl *********************
+ConstDecl::ConstDecl( string id,Type *ty,Scope *sc,Exp *e ):Decl(id,ty,0),scope(sc),exp(e){
+ sourceinfo=source_info;
+ _constDecls.push_back(this);
+}
+
+void ConstDecl::resolve(){
+ source_info=sourceinfo;
+ Val *v=exp->eval(scope,val->type);
+ if( !v->constant() ) fail( "Constant initializers must be constant" );
+ val->cg_exp=v->cg_exp;
+}
--- /dev/null
+
+#ifndef DECL_H
+#define DECL_H
+
+#include "val.h"
+
+struct Exp;
+struct ExpSeq;
+
+struct Decl{
+ string ident; //real ident
+ Val* val; //value of decl
+ string meta; //meta data
+
+ Decl( string id,Val *v );
+ Decl( string id,Type *ty,CGExp *cg );
+
+ void debugDecl( CGDat *d,int blockKind );
+
+ void setMetaData( string meta );
+
+ string debugEncoding();
+
+ static void resolveDecls();
+};
+
+struct FunDecl : public Decl{
+ string sourceinfo;
+ Scope *scope;
+ ExpSeq *defaults;
+
+ FunDecl( string id,FunType *ty,CGExp *cg,Scope *sc,ExpSeq *defs );
+
+ void resolve();
+};
+
+struct ConstDecl : public Decl{
+ string sourceinfo;
+ Scope *scope;
+ Exp *exp;
+
+ ConstDecl( string id,Type *ty,Scope *sc,Exp *e );
+
+ void resolve();
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "std.h"
+#include "declseq.h"
+#include "decl.h"
+
+void DeclSeq::push_back( Decl *d ){
+ if( !_map.insert( make_pair(tolower(d->ident),d->val) ).second ) dupid( d->ident );
+ _vec.push_back(d);
+}
+
+Val *DeclSeq::find( string id ){
+ map<string,Val*>::const_iterator it=_map.find(tolower(id));
+ return it==_map.end() ? 0 : it->second;
+}
+
+void DeclSeq::update( int i,Decl *d ){
+ _vec[i]=d;
+ _map.find(tolower(d->ident))->second=d->val;
+}
--- /dev/null
+
+#ifndef DECLSEQ_H
+#define DECLSEQ_H
+
+#include "scope.h"
+
+struct Val;
+struct Decl;
+
+struct DeclSeq : public Scope{
+ vector<Decl*> _vec;
+ map<string,Val*> _map;
+
+ void push_back( Decl *d );
+ Val* find( string id );
+ int size()const{ return _vec.size(); }
+ Decl* operator[]( int n )const{ return _vec[n]; }
+ void update( int i,Decl *d );
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "std.h"
+#include "exp.h"
+#include "toker.h"
+
+using namespace CG;
+
+//**************** Expression *********************
+Exp::~Exp(){
+}
+
+//internal eval
+Val *Exp::_eval( Scope *sc ){
+ fail( "TODO!" );
+ return 0;
+}
+
+Val *Exp::eval( Scope *sc ){
+ return _eval(sc);
+}
+
+Val *Exp::eval( Scope *sc,Type *ty ){
+ Val *v=_eval(sc);
+ return v->cast(ty);
+}
+
+Val *Exp::evalRef( Block *b ){
+ Val *v=_eval(b);
+ if( !v->type->refType() ) fail( "Expression must be a variable" );
+ v=b->linearizeRef(v);
+ return v;
+}
+
+Val *Exp::evalInit( Scope *sc,Type *ty ){
+ return _eval( sc )->initCast( ty );
+}
+
+//************ Expression sequence ****************
+ExpSeq::ExpSeq(){
+}
+
+ExpSeq::~ExpSeq(){
+}
+
+//************** Cast Expression ******************
+Val *CastExp::_eval( Scope *sc ){
+ Val *v=exp->eval(sc);
+ v=v->explicitCast( type );
+ return v;
+}
+
+//*************** Val Expression ******************
+Val *ValExp::_eval( Scope *sc ){
+ return val;
+}
+
+//************ Local Decl Expression **************
+Val *LocalDeclExp::_eval( Scope *sc ){
+
+ Block *b=dynamic_cast<Block*>(sc);
+ assert(b);
+
+ Val *v=new Val(type,tmp(type->cgType()));
+ Decl *d=new Decl( ident,v );
+
+ Val *i=Val::null(type);
+ FunBlock *func=b->fun_block;
+
+ if( strictMode ){
+ b->initRef( v,i );
+ block->declLocal( d );
+ }else{
+ b->assignRef( v,i );
+ func->declLocal( d );
+ }
+
+ if( !strictMode || opt_debug ){
+ func->cg_enter->push_back( mov(v->cg_exp,i->cg_exp) );
+ }
+
+ return v;
+}
+
+//************* Global Expression *****************
+Val *GlobalExp::_eval( Scope *sc ){
+ Val *v=mainFun->find(ident);
+ if( !v ) badid( ident );
+ return v;
+}
+
+//************** Ident Expression *****************
+Val *IdentExp::_eval( Scope *sc ){
+ Val *v=sc->find(ident);
+
+ if( !v ){
+ if( !strictMode ){
+ if( Block *b=dynamic_cast<Block*>(sc) ){
+ FunBlock *f=b->fun_block;
+ Type *ty=new RefType(type ? type : Type::int32);
+ v=new Val(ty,tmp(ty->cgType()));
+ f->cg_enter->push_back( mov(v->cg_exp,(new Val(Type::null,0))->cast(ty)->cg_exp) );
+ f->declLocal(new Decl(ident,v));
+ return v;
+ }
+ }
+ badid(ident);
+ }
+
+ if( !v->cg_exp ) fail( "Identifier '%s' is not a legal expression",ident.c_str() );
+
+ if( type ){
+ Type *ty=v->type;
+ if( FunType *t=ty->funType() ) ty=t->return_type;
+ else if( ArrayType *t=ty->arrayType() ) ty=t->element_type;
+ if( !type->equals(ty) ) fail( "Identifier type does not match declared type" );
+ }
+
+ return v;
+}
+
+//************** Member Expression ****************
+Val *MemberExp::_eval( Scope *sc ){
+ return rhs->eval( lhs->eval( sc ) );
+}
+
+//*************** Null Expression *****************
+Val *NullExp::_eval( Scope *sc ){
+ return new Val( Type::null,0 );
+}
+
+//*************** Self Expression *****************
+Val *SelfExp::_eval( Scope *sc ){
+ Block *b=dynamic_cast<Block*>(sc);
+ Val *v=b ? b->fun_block->fun_scope : 0;
+ if( !v ) fail( "'Self' can only be used within methods" );
+ return v;
+}
+
+//************** Super Expression *****************
+Val *SuperExp::_eval( Scope *sc ){
+ Block *b=dynamic_cast<Block*>(sc);
+ Val *v=b ? b->fun_block->fun_scope : 0;
+ if( !v ) fail( "'Super' can only be used within methods" );
+ return new SuperVal( v );
+}
+
+//*************** New Expression ******************
+Val *NewExp::_eval( Scope *sc ){
+
+ Val *v=exp->eval(sc);
+
+ ClassType *t=v->type->classType();
+
+ if( !t ){
+ ObjectType *o=v->type->objectType();
+ if( !o ) fail( "Subexpression for 'New' must be a user defined type or object" );
+ t=o->class_val->type->classType();
+ assert(t);
+ v=new Val( t,mem(CG_PTR,v->cg_exp,0) );
+ }else if( t->attrs & ClassType::ABSTRACT ){
+ string tyname="?";
+ if( IdentExp *ie=dynamic_cast<IdentExp*>(exp) ) tyname=ie->ident;
+ set<string> ids;
+ while( t ){
+ int k;
+ for( k=0;k<t->methods.size();++k ){
+ Decl *d=t->methods[k];
+ if( ids.count(d->ident) ) continue;
+ if( FunType *f=d->val->type->funType() ){
+ if( f->attrs & FunType::ABSTRACT ){
+ fail( "Unable to create new object of abstract type '%s' due to abstract method '%s'",tyname.c_str(),d->ident.c_str() );
+ }
+ }
+ ids.insert(d->ident);
+ }
+ t=t->superClass();
+ }
+ fail( "Unable to create new object of abstract type '%s'",tyname.c_str() );
+ }else if( t->attrs & ClassType::EXTERN ){
+ fail( "'New' can not be used to create extern objects" );
+ }
+
+ Type *type=new ObjectType(v);
+ v=new Val(type,jsr(CG_PTR,"bbObjectNew",v->cg_exp));
+ return v;
+}
+
+//************** Array Expression *****************
+Val *ArrayExp::_eval( Scope *sc ){
+
+ if( !type ){
+ Val *v=exp->eval(sc);
+ type=v->type;
+ if( !type->classType() ) fail( "Subexpression for 'New array' must be a Type" );
+ type=new ObjectType(v);
+ }
+
+ ArrayType *arr=new ArrayType( type,dims.size() );
+
+ string e=type->encoding();
+ if( e.size() && e[0]==':' && type->exObjectType() ) e='?'+e.substr(1);
+
+ CGDat *d=dat();
+ d->push_back( lit(tobstring(e),CG_CSTRING) );
+
+ CGJsr *cg;
+ if( dims.size()==1 ){
+ cg=jsr(CG_PTR,"bbArrayNew1D",d,dims[0]->eval(sc,Type::int32)->cg_exp);
+ }else{
+ cg=jsr(CG_PTR,"bbArrayNew",d,lit((int)dims.size()) );
+ for( int k=0;k<dims.size();++k ){
+ cg->args.push_back( dims[k]->eval(sc,Type::int32)->cg_exp );
+ }
+ }
+
+ Val *v=new Val(arr,cg);
+ return v;
+}
+
+//************ AutoArray Expression ***************
+Val *ArrayDataExp::_eval( Scope *sc ){
+ if( !exps.size() ) return new Val( Type::null,0 );
+
+ int k;
+ Type *ty=0;
+ vector<Val*> vals;
+
+ for( k=0;k<exps.size();++k ){
+ Val *v=exps[k]->eval(sc);
+ if( !v->type || v->type->nullType() ){
+ fail( "Auto array element has no type" );
+ }
+ if( !ty ){
+ ty=v->type;
+ }else{
+ if( !ty->equals(v->type) ) fail( "Auto array elements must have identical types" );
+ }
+ vals.push_back( v );
+ }
+
+ vector<CGStm*> stms;
+
+ CGTmp *t=tmp(CG_PTR);
+ stms.push_back( mov(t,jsr(CG_PTR,"bbArrayNew1D",genCString(ty->encoding()),lit((int)vals.size()))) );
+
+ for( k=0;k<vals.size();++k ){
+ Val *v=vals[k]->cast( ty );
+ if( ty->objectType() && !opt_threaded ){
+ v=v->retain();
+ }
+ stms.push_back( mov(mem(ty->cgType(),t,k*ty->size()+24),v->cg_exp) );
+ }
+
+ return new Val( new ArrayType(ty,1),esq( seq(stms),t ) );
+}
+
+//************ Intrinsic Expression ***************
+Val *IntrinsicExp::_eval( Scope *sc ){
+ if( toke==T_VARPTR ){
+ if( type ) fail( "No return type permitted for 'Varptr'" );
+
+ Val *v=exp->eval(sc);
+ RefType *t=v->type->refType();
+ if( !t ) fail( "Subexpression for 'Ptr' must be a variable" );
+
+ Type *type=new PtrType(t->val_type);
+
+ return new Val(type,lea(v->cg_exp));
+
+ }else if( toke==T_LEN ){
+ if( type && type->encoding()!="i" ) fail( "Return type for 'Len' must be Int" );
+
+ Val *v=exp->eval(sc);
+ if( v->type->stringType() ){
+ if( v->constant() ) return new Val((int)v->stringValue().size());
+ return new Val(Type::int32,mem(CG_INT32,v->cg_exp,8));
+ }else if( v->type->arrayType() ){
+ return new Val(Type::int32,mem(CG_INT32,v->cg_exp,20));
+ }
+ return new Val(Type::int32,lit1);
+
+ }else if( toke==T_SIZEOF ){
+ if( type && type->encoding()!="i" ) fail( "Return type for 'SizeOf' must be Int" );
+
+ Val *v=exp->eval(sc);
+ if( v->type->stringType() ){
+ if( v->constant() ) return new Val((int)v->stringValue().size()*2);
+ return new Val(Type::int32,bop(CG_MUL,mem(CG_INT32,v->cg_exp,8),lit(2)));
+ }else if( v->type->arrayType() ){
+ return new Val(Type::int32,mem(CG_INT32,v->cg_exp,16));
+ }else if( ObjectType *t=v->type->objectType() ){
+ return new Val(Type::int32,lit(t->objectClass()->sizeof_fields-8));
+ }else if( ClassType *t=v->type->classType() ){
+ if( t->attrs & ClassType::EXTERN ){
+ }else{
+ return new Val(Type::int32,lit(t->sizeof_fields-8));
+ }
+ }
+ return new Val(Type::int32,lit(v->type->size()));
+
+ }else if( toke==T_CHR ){
+ if( type && type->encoding()!="$" ) fail( "Return type for 'Chr' must be String" );
+
+ Val *v=exp->eval(sc,Type::int32);
+ if( v->constant() ){
+ return new Val( bstring(1,(bchar_t)v->intValue()) );
+ }
+ return new Val( Type::stringObject,jsr(CG_PTR,"bbStringFromChar",v->cg_exp) );
+
+ }else if( toke==T_ASC ){
+ if( type && type->encoding()!="i" ) fail( "Return type for 'Asc' must be Int" );
+
+ Val *v=exp->eval(sc,Type::stringObject);
+ if( v->constant() ){
+ if( v->stringValue().size() ) return new Val( (int)v->stringValue()[0] );
+ return new Val(-1);
+ }
+ return new Val( Type::int32,jsr(CG_INT32,"bbStringAsc",v->cg_exp) );
+
+ }else if( toke==T_INCBINPTR ){
+ if( type && type->encoding()!="*b" ) fail( "Return type for 'IncbinPtr' must be Byte Ptr" );
+
+ Val *v=exp->eval(sc,Type::stringObject);
+ return new Val( Type::bytePtr,jsr(CG_PTR,"bbIncbinPtr",v->cg_exp) );
+
+ }else if( toke==T_INCBINLEN ){
+ if( type && type->encoding()!="i" ) fail( "Return type for 'IncbinLen' must be Int" );
+
+ Val *v=exp->eval(sc,Type::stringObject);
+ return new Val( Type::int32,jsr(CG_INT32,"bbIncbinLen",v->cg_exp) );
+
+ }else{
+
+ fail( "Internal error" );
+ }
+ return 0;
+}
+
+//************* ExpSeq Expression *****************
+Val *ExpSeqExp::_eval( Scope *sc ){
+ assert(0);
+ return 0;
+}
+
+Val *ExpSeqExp::invokeFun( Val *v,FunType *fun,Scope *sc ){
+
+ if( seq.size()>fun->args.size() ) fail( "Too many function parameters" );
+
+ vector<Val*> args;
+ vector<CGExp*> cg_args;
+ CGSeq *cleanup=CG::seq(0);
+
+ int k;
+ for( k=0;k<fun->args.size();++k ){
+ Decl *d=fun->args[k];
+ Type *ty=d->val->type;
+ if( k<seq.size() && seq[k] ){
+ Val *t=seq[k]->eval(sc)->funArgCast(ty,cleanup);
+ args.push_back(t);
+ }else if( CGExp *e=d->val->cg_exp ){
+ args.push_back( new Val(d->val->type,e) );
+ }else{
+ fail( "Missing function parameter '%s'",d->ident.c_str() );
+ }
+ cg_args.push_back( args.back()->cg_exp );
+ }
+
+ Type *ty=fun->return_type;
+ CGExp *e=jsr( ty->cgType(),fun->call_conv,v->cg_exp,cg_args );
+
+ if( ty->cstringType() ){
+ ty=Type::stringObject;
+ e=jsr( CG_PTR,"bbStringFromCString",e );
+ }else if( ty->wstringType() ){
+ ty=Type::stringObject;
+ e=jsr( CG_PTR,"bbStringFromWString",e );
+ }
+
+ if( cleanup->stms.size() ){
+ CGTmp *t=tmp( ty->cgType() );
+ CGSeq *tseq=CG::seq(0);
+ tseq->push_back( mov(t,e) );
+ tseq->push_back( cleanup );
+ e=esq( tseq,t );
+ }
+
+ return new Val( ty,e );
+}
+
+Val *ExpSeqExp::performCast( Val *lhs,Scope *sc ){
+
+ if( seq.size()!=1 ) fail( "Illegal subexpression for object cast" );
+
+ Val *rhs=seq[0]->eval(sc);
+
+ return rhs->explicitCast( new ObjectType(lhs) );
+}
+
+Val *ExpSeqExp::indexString( Val *v,Scope *sc ){
+ if( seq.size()!=1 ) fail( "Illegal subexpression for string index" );
+
+ CGExp *p=v->cg_exp;
+
+ CGExp *e=seq[0]->eval( sc,Type::int32 )->cg_exp;
+
+ if( opt_debug ){
+ p=tmp(CG_PTR);
+ CGTmp *t=tmp(CG_INT32);
+ CGSym *q=sym();
+ CGStm *stms=CG::seq(
+ mov(p,v->cg_exp),
+ mov(t,e),
+ bcc(CG_LTU,t,mem(CG_INT32,p,8),q),
+ eva(jsr(CG_INT32,"brl_blitz_ArrayBoundsError")),
+ lab(q),
+ 0 );
+ e=esq(stms,t);
+ }
+
+ e=cvt( CG_INT32,mem( CG_INT16,bop(CG_ADD,p,bop(CG_MUL,e,lit(2))),12 ) );
+ return new Val(Type::int32,e);
+
+// Val *i=seq[0]->eval( sc,Type::int32 );
+// CGExp *e=cvt( CG_INT32,mem( CG_INT16,bop(CG_ADD,v->cg_exp,bop(CG_MUL,i->cg_exp,lit(2))),12 ) );
+// return new Val(Type::int32,e);
+}
+
+Val *ExpSeqExp::indexArray( Val *v,ArrayType *arr,Scope *sc ){
+
+ if( arr->dims!=seq.size() ) fail( "Incorrect number of array dimensions" );
+
+ CGExp *cg_exp=v->cg_exp,*p=0;
+
+ bool sidefx=cg_exp->sideEffects();
+ if( sidefx ) cg_exp=tmp(CG_PTR);
+
+ for( int k=0;k<seq.size();++k ){
+
+ Val *v=seq[k]->eval(sc)->cast( Type::int32 );
+
+ CGExp *e=v->cg_exp;
+
+ if( k<seq.size()-1 ) e=bop(CG_MUL,e,mem(CG_INT32,cg_exp,k*4+24));
+
+ if( opt_debug ){
+ CGTmp *t=tmp(CG_INT32);
+ CGSym *q=sym();
+ CGStm *stms=CG::seq(
+ mov(t,e),
+ bcc(CG_LTU,t,mem(CG_INT32,cg_exp,k*4+20),q),
+ eva(jsr(CG_INT32,"brl_blitz_ArrayBoundsError")),
+ lab(q),
+ 0 );
+ e=esq(stms,t);
+ }
+
+ if( p ) p=bop(CG_ADD,p,e);
+ else p=e;
+ }
+
+ Type *ty=arr->element_type;
+
+ p=bop(CG_ADD,cg_exp,bop(CG_MUL,p,lit(ty->size())));
+
+ if( sidefx ) p=esq( mov(cg_exp,v->cg_exp),p );
+
+ p=mem(ty->cgType(),p,seq.size()*4+20);
+
+ return new Val(ty,p);
+}
+
+Val *ExpSeqExp::indexPointer( Val *v,Type *t,Scope *sc ){
+ if( seq.size()!=1 ) fail( "Illegal subexpression for pointer index" );
+
+ Val *i=seq[0]->eval( sc,Type::int32 );
+ CGExp *e=mem( t->cgType(),
+ bop(CG_ADD,v->cg_exp,
+ bop(CG_MUL,i->cg_exp,lit(t->size()))),0);
+ Type *type=new RefType(t);
+ return new Val(type,e);
+}
+
+//************* Invoke Expression *****************
+Val *InvokeExp::_eval( Scope *sc ){
+ Val *v=exp->eval(sc);
+ Type *type=v->type;
+
+ if( FunType *t=type->funType() ){
+ return invokeFun( v,t,sc );
+ }else if( ClassType *t=type->classType() ){
+ return performCast( v,sc );
+ }else if( ArrayType *t=type->arrayType() ){
+ if( !strictMode ) return indexArray( v,t,sc );
+ }
+ if( !strictMode ){
+ if( IdentExp *ie=dynamic_cast<IdentExp*>(exp) ){
+ fail( "Identifier '%s' not found",ie->ident.c_str() );
+ }
+ }
+ fail( "Expression of type '%s' cannot be invoked",type->toString().c_str() );
+ return 0;
+}
+
+//************** Index Expression *****************
+Val *IndexExp::_eval( Scope *sc ){
+
+ Val *v=exp->eval(sc);
+ Type *type=v->type;
+
+ if( ArrayType *t=type->arrayType() ){
+ return indexArray( v,t,sc );
+ }else if( PtrType *t=type->ptrType() ){
+ return indexPointer( v,t->val_type,sc );
+ }else if( type->stringType() ){
+ return indexString( v,sc );
+ }
+ fail( "Expression of type '%s' cannot be indexed",type->toString().c_str() );
+ return 0;
+}
+
+//************** Slice Expression *****************
+Val *SliceExp::_eval( Scope *sc ){
+
+ Val *v=exp->eval(sc);
+
+ ArrayType *arr=v->type->arrayType();
+ StringType *str=v->type->stringType();
+
+ if( (!arr && !str) || (arr && arr->dims!=1) ) fail( "Slices can only be used with strings or one dimensional arrays" );
+
+ CGExp *e=v->cg_exp,*t=0;
+ if( !rhs && v->cg_exp->sideEffects() ){
+ t=e;
+ e=tmp(CG_PTR);
+ }
+
+ CGExp *l=lhs ? lhs->eval(sc,Type::int32)->cg_exp : lit0;
+ CGExp *r=rhs ? rhs->eval(sc,Type::int32)->cg_exp : mem(CG_INT32,e,arr ? 20 : 8);
+
+ if( str ){
+ l=jsr(CG_PTR,"bbStringSlice",e,l,r);
+ }else{
+ CGExp *ty=genCString( arr->element_type->encoding() );
+ l=jsr(CG_PTR,"bbArraySlice",ty,e,l,r);
+ }
+
+ Type *ty=v->type;
+ if( RefType *r=ty->refType() ) ty=r->val_type;
+
+ if( !t ) return new Val( ty,l );
+
+ return new Val( ty,esq(mov(e,t),l) );
+}
+
+//************* Compare Expression ****************
+Val *CmpExp::_eval( Scope *sc ){
+
+ Val *l=lhs->eval(sc);
+ Val *r=rhs->eval(sc);
+
+ if( l->type->ptrType() && r->type->nullType() ) r=r->cast(l->type);
+ else if( r->type->ptrType() && l->type->nullType() ) l=l->cast(r->type);
+
+ if( PtrType *px=l->type->ptrType() ){
+ if( PtrType *py=r->type->ptrType() ){
+ if( px->val_type->equals( py->val_type ) ){
+ int cgop;
+ switch( op ){
+ case T_LT:cgop=CG_LT;break;
+ case T_EQ:cgop=CG_EQ;break;
+ case T_GT:cgop=CG_GT;break;
+ case T_LE:cgop=CG_LE;break;
+ case T_GE:cgop=CG_GE;break;
+ case T_NE:cgop=CG_NE;break;
+ }
+ return new Val(Type::int32,scc(cgop,l->cg_exp,r->cg_exp));
+ }
+ }
+ }
+
+ if( l->type->ptrType() || r->type->ptrType() ){
+ fail( "Pointer type mismatch" );
+ }
+
+ Type *ty=l->balance(r);
+
+ if( ty->numericType() ){
+ }else if( ty->stringType() ){
+ }else if( ObjectType *obj=ty->objectType() ){
+ if( op!=T_EQ && op!=T_NE ) fail( "Operator '%s' cannot be applied to objects",Toker::toString(op).c_str() );
+ }else if( ObjectType *obj=ty->exObjectType() ){
+ if( op!=T_EQ && op!=T_NE ) fail( "Operator '%s' cannot be applied to extern objects",Toker::toString(op).c_str() );
+ }else if( FunType *fun=ty->funType() ){
+ if( (op!=T_EQ && op!=T_NE) || (fun->attrs & FunType::METHOD) ){
+ const char *p=(fun->attrs & FunType::METHOD) ? "methods" : "functions";
+ fail( "Operator '%s' cannot be applied to %s",Toker::toString(op).c_str(),p );
+ }
+ }else if( ty->nullType() ){
+ if( op!=T_EQ && op!=T_NE ) fail( "Operator '%s' cannot be applied to 'Null'",Toker::toString(op).c_str() );
+ return new Val( op==T_EQ ? 1 : 0);
+ }else{
+ fail( "Operands cannot be compared" );
+ }
+
+ l=l->cast(ty);
+ r=r->cast(ty);
+
+ if( l->constant() && r->constant() ){
+ int z;
+ if( ty->intType() ){
+ int64 x=l->intValue(),y=r->intValue();
+ switch(op){
+ case T_LT:z=x<y;break;
+ case T_EQ:z=x==y;break;
+ case T_GT:z=x>y;break;
+ case T_LE:z=x<=y;break;
+ case T_GE:z=x>=y;break;
+ case T_NE:z=x!=y;break;
+ }
+ }else if( ty->floatType() ){
+ double x=l->floatValue(),y=r->floatValue();
+ switch(op){
+ case T_LT:z=x<y;break;
+ case T_EQ:z=x==y;break;
+ case T_GT:z=x>y;break;
+ case T_LE:z=x<=y;break;
+ case T_GE:z=x>=y;break;
+ case T_NE:z=x!=y;break;
+ }
+ }else if( ty->stringType() ){
+ bstring x=l->stringValue(),y=r->stringValue();
+ switch(op){
+ case T_LT:z=x<y;break;
+ case T_EQ:z=x==y;break;
+ case T_GT:z=x>y;break;
+ case T_LE:z=x<=y;break;
+ case T_GE:z=x>=y;break;
+ case T_NE:z=x!=y;break;
+ }
+ }else{
+ fail( "Operands cannot be compared" );
+ }
+ return new Val(z);
+ }
+
+ int cgop;
+ switch( op ){
+ case T_LT:cgop=CG_LT;break;
+ case T_EQ:cgop=CG_EQ;break;
+ case T_GT:cgop=CG_GT;break;
+ case T_LE:cgop=CG_LE;break;
+ case T_GE:cgop=CG_GE;break;
+ case T_NE:cgop=CG_NE;break;
+ }
+
+ Val *t;
+ if( ty->stringType() ){
+ t=new Val(Type::int32,scc(cgop,jsr(CG_INT32,"bbStringCompare",l->cg_exp,r->cg_exp),lit0));
+ }else{
+ t=new Val(Type::int32,scc(cgop,l->cg_exp,r->cg_exp));
+ }
+ return t;
+}
+
+//************ Short Circuit Expression ***********
+Val *ShortCircExp::_eval( Scope *sc ){
+
+ Val *lv=lhs->eval(sc)->cond();
+ Val *rv=rhs->eval(sc)->cond();
+
+ int cg_op=op==T_AND ? CG_EQ : CG_NE;
+
+ //result reg
+ CGSym *e=sym();
+ CGTmp *r=tmp(CG_INT32);
+
+ CGStm *stms=seq(
+ mov(r,lv->cg_exp),
+ bcc(cg_op,r,lit0,e),
+ mov(r,rv->cg_exp),
+ lab(e),
+ 0 );
+
+ return new Val(Type::int32,esq(stms,r));
+}
+
+//***************** Not Expression ****************
+Val *NotExp::_eval( Scope *sc ){
+
+ Val *v=exp->eval(sc)->cond();
+
+ if( v->constant() ) return new Val( !v->intValue() );
+
+ return new Val(Type::int32,scc(CG_EQ,v->cg_exp,lit0));
+}
+
+//**************** Unary Expression ***************
+Val *UnaryExp::_eval( Scope *sc ){
+ Val *v=exp->eval(sc);
+ Type *ty=v->type;
+
+ if( !ty->numericType() ){
+ fail( "Subexpression for '%s' must be of numeric type",Toker::toString(op).c_str() );
+ }
+
+ switch( op ){
+ case '+':
+ return v;
+ case '~':
+ if( !v->type->intType() ) fail( "Bitwise complement can only be used with integers" );
+ if( v->type->cgType()!=CG_INT64 ) v=v->cast( Type::int32 );
+ break;
+ }
+
+ ty=v->type;
+
+ if( v->constant() ){
+ if( ty->intType() ){
+ int64 n=v->intValue();
+ switch( op ){
+ case '-':n=-n;break;
+ case '~':n=~n;break;
+ case T_ABS:n=(n>=0) ? n : -n;break;
+ case T_SGN:n=(n==0) ? 0 : (n>0 ? 1 : -1);break;
+ default:assert(0);
+ }
+ return new Val(n,ty);
+ }else{
+ double n=v->floatValue();
+ switch( op ){
+ case '-':n=-n;break;
+ case T_ABS:n=fabs(n);break;
+ case T_SGN:n=(n==0) ? 0 : (n>0 ? 1 : -1);break;
+ default:assert(0);
+ }
+ return new Val(n,ty);
+ }
+ assert(0);
+ }
+
+ int cgop;
+ switch( op ){
+ case '-':cgop=CG_NEG;break;
+ case '~':cgop=CG_NOT;break;
+ case T_ABS:cgop=CG_ABS;break;
+ case T_SGN:cgop=CG_SGN;break;
+ default:assert(0);
+ }
+
+ return new Val(ty,uop(cgop,v->cg_exp));
+}
+
+//**************** Arith Expression ***************
+Val *ArithExp::pointerArith( Val *lv,Val *rv ){
+
+ PtrType *lp=lv->type->ptrType();
+ PtrType *rp=rv->type->ptrType();
+ PtrType *ty=lp ? lp : rp;
+
+ CGLit *sz=lit( ty->val_type->size() );
+
+ if( lp && rp ){
+ if( op!='-' ) fail( "Illegal pointer arithmetic operator" );
+ if( !lp->equals(rp) ) fail( "Pointer types are not equivalent" );
+ CGExp *e=bop(CG_DIV,bop(CG_SUB,lv->cg_exp,rv->cg_exp),sz);
+ return new Val(Type::int32,e);
+ }
+ CGExp *e=0;
+ if( lp ){
+ rv=rv->cast(Type::int32);
+ if( op=='+' ) e=bop(CG_ADD,lv->cg_exp,bop(CG_MUL,rv->cg_exp,sz));
+ else if( op=='-' ) e=bop(CG_SUB,lv->cg_exp,bop(CG_MUL,rv->cg_exp,sz));
+ }else{
+ lv=lv->cast(Type::int32);
+ if( op=='+' ) e=bop(CG_ADD,rv->cg_exp,bop(CG_MUL,lv->cg_exp,sz));
+ }
+ if( !e ) fail( "Illegal pointer arithmetic operator" );
+ return new Val( ty,e );
+}
+
+Val *ArithExp::_eval( Scope *sc ){
+ Val *l=lhs ? lhs->eval(sc) : lhs_val;
+ Val *r=rhs ? rhs->eval(sc) : rhs_val;
+
+ if( l->type->ptrType() || r->type->ptrType() ) return pointerArith(l,r);
+
+ Type *ty=0;
+
+ if( op=='^' ){
+ ty=Type::float64;
+ }else if( ArrayType *p=l->type->arrayType() ){
+ if( ArrayType *q=r->type->arrayType() ){
+ if( p->dims==q->dims ){
+ if( p->element_type->equals( q->element_type ) ){
+ ty=p;
+ }else if( ObjectType *pt=p->element_type->objectType() ){
+ if( ObjectType *qt=q->element_type->objectType() ){
+ if( pt->extends(qt) ){
+ ty=q;
+ }else if( qt->extends(pt) ){
+ ty=p;
+ }else{
+ ty=new ArrayType( Type::objectObject,p->dims );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( !ty ) ty=l->balance(r);
+
+ if( ty->nullType() ){
+ fail( "Operator '%s' cannot be used with null",Toker::toString(op).c_str() );
+ }else if( ty->arrayType() ){
+ if( op!='+' ) fail( "Operator '%s' can not be used with arrays",Toker::toString(op).c_str() );
+ }else if( ty->stringType() ){
+ if( op!='+' ) fail( "Operator '%s' can not be used with strings",Toker::toString(op).c_str() );
+
+ }else if( !ty->numericType() ){
+ fail( "Operator '%s' can only be used with numeric types",Toker::toString(op).c_str() );
+ }
+
+ l=l->cast(ty);
+ r=r->cast(ty);
+
+ if( l->constant() && r->constant() ){
+ if( ty->intType() ){
+ int64 x=l->intValue(),y=r->intValue();
+ switch( op ){
+ case '+':x+=y;break;
+ case '-':x-=y;break;
+ case '*':x*=y;break;
+ case '/':if( !y ) fail( "Integer division by zero" );x/=y;break;
+ case '^':x=(int)pow((double)x,(double)y);break;
+ case T_MOD:if( !y ) fail( "Integer division by zero" );x%=y;break;
+ case T_MIN:x=x<y ? x : y;break;
+ case T_MAX:x=x>y ? x : y;break;
+ default:assert(0);
+ }
+ return new Val(x,ty);
+ }else if( ty->floatType() ){
+ double x=l->floatValue(),y=r->floatValue();
+ switch( op ){
+ case '+':x+=y;break;
+ case '-':x-=y;break;
+ case '*':x*=y;break;
+ case '/':x/=y;break;
+ case '^':x=pow(x,y);break;
+ case T_MOD:x=fmod(x,y);break;
+ case T_MIN:x=x<y ? x : y;break;
+ case T_MAX:x=x>y ? x : y;break;
+ default:assert(0);
+ }
+ return new Val(x,ty);
+ }else if( ty->stringType() ){
+ bstring x=l->stringValue(),y=r->stringValue();
+ switch( op ){
+ case '+':x+=y;break;
+ default:assert(0);
+ }
+ return new Val(x);
+ }
+ assert(0);
+ }
+
+ if( ArrayType *t=ty->arrayType() ){
+ if( l->type->arrayType()->dims!=1 || r->type->arrayType()->dims!=1 ){
+ fail( "Multi-dimensional arrays can not be concatenated" );
+ }
+ CGExp *e=jsr(CG_PTR,"bbArrayConcat",genCString(t->element_type->encoding()),l->cg_exp,r->cg_exp );
+ return new Val(ty,e);
+ }
+
+ if( ty->stringType() ){
+ CGExp *e=jsr(CG_PTR,"bbStringConcat",l->cg_exp,r->cg_exp );
+ return new Val(ty,e);
+ }
+
+ if( op=='^' ){
+ CGExp *e=jsr(CG_FLOAT64,"bbFloatPow",l->cg_exp,r->cg_exp );
+ return new Val(ty,e);
+ }
+
+ int cgop;
+ switch( op ){
+ case '+':cgop=CG_ADD;break;
+ case '-':cgop=CG_SUB;break;
+ case '*':cgop=CG_MUL;break;
+ case '/':cgop=CG_DIV;break;
+ case T_MOD:cgop=CG_MOD;break;
+ case T_MIN:cgop=CG_MIN;break;
+ case T_MAX:cgop=CG_MAX;break;
+ default:assert(0);
+ }
+
+ return new Val(ty,bop(cgop,l->cg_exp,r->cg_exp));
+}
+
+//*************** Bitwise Expression **************
+Val *BitwiseExp::_eval( Scope *sc ){
+
+ Val *l=lhs ? lhs->eval(sc) : lhs_val;
+ Val *r=rhs ? rhs->eval(sc) : rhs_val;
+
+ if( !l->type->intType() || !r->type->intType() ) fail( "Bitwise operators can only be used with integers" );
+
+ Type *ty=Type::int32;
+ if( l->type->cgType()==CG_INT64 || r->type->cgType()==CG_INT64) ty=Type::int64;
+
+ l=l->cast(ty);
+ r=r->cast(ty);
+
+ if( l->constant() && r->constant() ){
+ int64 x=l->intValue(),y=r->intValue();
+ switch( op ){
+ case '&':x&=y;break;
+ case '|':x|=y;break;
+ case '~':x^=y;break;
+ case T_SHL:x<<=y;break;
+ case T_SAR:x>>=y;break;
+ case T_SHR:x=(unsigned)x>>(unsigned)y;break;
+ default:assert(0);
+ }
+ return new Val(x,ty);
+ }
+
+ int cgop;
+ switch( op ){
+ case '&':cgop=CG_AND;break;
+ case '|':cgop=CG_ORL;break;
+ case '~':cgop=CG_XOR;break;
+ case T_SHL:cgop=CG_SHL;break;
+ case T_SHR:cgop=CG_SHR;break;
+ case T_SAR:cgop=CG_SAR;break;
+ default:assert(0);
+ }
+
+ return new Val(ty,bop(cgop,l->cg_exp,r->cg_exp));
+}
--- /dev/null
+
+#ifndef EXP_H
+#define EXP_H
+
+#include "block.h"
+
+struct Exp{
+
+ virtual ~Exp();
+
+ Val *evalRef( Block *block );
+
+ Val *eval( Scope *scope );
+ Val *eval( Scope *scope,Type *type );
+ Val *evalInit( Scope *scope,Type *type );
+
+protected:
+ virtual Val *_eval( Scope *scope );
+};
+
+struct ExpSeq : public vector<Exp*>{
+ ExpSeq();
+ virtual ~ExpSeq();
+};
+
+struct ValExp : public Exp{
+ Val *val;
+
+ ValExp( Val *v ):val(v){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct CastExp : public Exp{
+ Type *type;
+ Exp *exp;
+
+ CastExp( Type *t,Exp *e ):type(t),exp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct NullExp : public Exp{
+ Val *_eval( Scope *scope );
+};
+
+struct LocalDeclExp : public Exp{
+ string ident;
+ Type *type;
+ Block *block;
+
+ LocalDeclExp( string id,Type *ty,Block *b ):ident(id),type(ty),block(b){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct GlobalExp : public Exp{
+ string ident;
+
+ GlobalExp( string id ):ident(id){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct IdentExp : public Exp{
+ string ident;
+ Type *type;
+
+ IdentExp( string id,Type *ty ):ident(id),type(ty){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct MemberExp : public Exp{
+ Exp *lhs,*rhs;
+
+ MemberExp( Exp *l,Exp *r ):lhs(l),rhs(r){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct SelfExp : public Exp{
+ Val *_eval( Scope *scope );
+};
+
+struct SuperExp : public Exp{
+ Val *_eval( Scope *scope );
+};
+
+struct NewExp : public Exp{
+ Exp *exp;
+
+ NewExp( Exp *e ):exp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct ArrayExp : public Exp{
+ Exp *exp;
+ Type *type;
+
+ ExpSeq dims;
+
+ ArrayExp( Exp *e ):exp(e),type(0){}
+ ArrayExp( Type *t ):exp(0),type(t){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct ArrayDataExp : public Exp{
+ ExpSeq exps;
+
+ Val *_eval( Scope *scope );
+};
+
+struct IntrinsicExp : public Exp{
+ int toke;
+ Type *type;
+ Exp *exp;
+
+ IntrinsicExp( int t,Type *ty,Exp *e ):toke(t),type(ty),exp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct ExpSeqExp : public Exp{
+ Exp *exp;
+ ExpSeq seq;
+
+ ExpSeqExp( Exp *e ):exp(e){}
+
+ Val *_eval( Scope *scope );
+
+ Val *invokeFun( Val *v,FunType *t,Scope *sc );
+ Val *performCast( Val *v,Scope *sc );
+
+ Val *indexString( Val *v,Scope *sc );
+ Val *indexArray( Val *v,ArrayType *t,Scope *sc );
+ Val *indexPointer( Val *v,Type *t,Scope *sc );
+};
+
+struct InvokeExp : public ExpSeqExp{
+
+ InvokeExp( Exp *e ):ExpSeqExp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct IndexExp : public ExpSeqExp{
+
+ IndexExp( Exp *e ):ExpSeqExp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct SliceExp : public Exp{
+ int toke;
+ Exp *exp;
+ Exp *lhs,*rhs;
+
+ SliceExp( int t,Exp *e,Exp *l,Exp *r ):toke(t),exp(e),lhs(l),rhs(r){}
+
+ Val *_eval( Scope *scope );
+};
+
+//<, =, >, <=, >=, <>
+struct CmpExp : public Exp{
+ int op;
+ Exp *lhs,*rhs;
+
+ CmpExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct ShortCircExp : public Exp{
+ int op;
+ Exp *lhs,*rhs;
+
+ ShortCircExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r){}
+
+ Val *_eval( Scope *scope );
+};
+
+struct NotExp : public Exp{
+ Exp *exp;
+
+ NotExp( Exp *e ):exp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+//-, Abs
+struct UnaryExp : public Exp{
+ int op;
+ Exp *exp;
+
+ UnaryExp( int o,Exp *e ):op(o),exp(e){}
+
+ Val *_eval( Scope *scope );
+};
+
+//+, -, *, /, Mod, Min, Max
+struct ArithExp : public Exp{
+ int op;
+ Exp *lhs,*rhs;
+ Val *lhs_val,*rhs_val;
+
+ ArithExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r),lhs_val(0),rhs_val(0){}
+ ArithExp( int o,Val *l,Exp *r ):op(o),lhs(0),rhs(r),lhs_val(l),rhs_val(0){}
+
+ Val *pointerArith( Val *pv,Val *iv );
+
+ Val *_eval( Scope *scope );
+};
+
+//And, Or, Xor, Shl, Shr, Sar
+struct BitwiseExp : public Exp{
+ int op;
+ Exp *lhs,*rhs;
+ Val *lhs_val,*rhs_val;
+
+ BitwiseExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r),lhs_val(0),rhs_val(0){}
+ BitwiseExp( int o,Val *l,Exp *r ):op(o),lhs(0),rhs(r),lhs_val(l),rhs_val(0){}
+
+ Val *_eval( Scope *scope );
+};
+
+#endif
--- /dev/null
+bmk0 -a -r -z -o ~/blitzmax/bin/bcc bcc.cpp
--- /dev/null
+
+#include "std.h"
+#include "module.h"
--- /dev/null
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#endif
--- /dev/null
+
+#include "std.h"
+#include "output.h"
+#include "decl.h"
+#include "val.h"
+
+ostream &out::operator<<( ostream &out,CGExp *exp ){
+
+ if( CGLit *t=exp->lit() ){
+ if( t->isint() ){
+ out<<fromint(t->int_value);
+ if( t->type==CG_INT64 ) out<<":Long";
+ }else if( t->isfloat() ){
+ if( isnan( t->float_value ) ){
+ out<<"nan";
+ }else if( isinf( t->float_value ) ){
+ out<<( t->float_value>0 ? "inf" : "-inf" );
+ }else{
+ out<<t->float_value;
+ }
+ out<<( t->type==CG_FLOAT32 ? '#' : '!' );
+ }else{
+ assert(0);
+ }
+ }else if( CGSym *t=exp->sym() ){
+ out<<"\""<<t->value<<"\"";
+ }else{
+ const char *ty="";
+ switch( exp->type ){
+ case CG_INT8:ty=":b";break;
+ case CG_INT16:ty=":s";break;
+ case CG_INT32:break;
+ case CG_INT64:ty=":l";break;
+ case CG_PTR:ty=":p";break;
+ case CG_FLOAT32:ty=":f";break;
+ case CG_FLOAT64:ty=":d";break;
+ default:
+ cout<<"type error:"<<exp->type<<endl;
+ assert(0);
+ }
+ if( CGMem *t=exp->mem() ){
+ out<<"mem"<<ty<<"("<<t->exp;
+ if( t->offset ) out<<","<<t->offset;
+ out<<")";
+ }else{
+ fail( "Unrecognized intermediate code expression - !*#%" );
+ }
+ }
+ return out;
+}
+
+ostream &out::operator<<( ostream &out,Type *ty ){
+ if( RefType *t=ty->refType() ){
+ out<<t->val_type<<'&';
+ }else if( VarType *t=ty->varType() ){
+ out<<t->val_type<<" Var";
+ }else if( PtrType *t=ty->ptrType() ){
+ out<<t->val_type<<'*';
+ }else if( IntType *t=ty->intType() ){
+ switch( t->size() ){
+ case 1:out<<"@";break;
+ case 2:out<<"@@";break;
+ case 4:out<<"%";break;
+ case 8:out<<"%%";break;
+ default:assert(0);
+ }
+ }else if( FloatType *t=ty->floatType() ){
+ switch( t->size() ){
+ case 4:out<<"#";break;
+ case 8:out<<"!";break;
+ default:assert(0);
+ }
+ }else if( CStringType *t=ty->cstringType() ){
+ out<<"$z";
+ }else if( WStringType *t=ty->wstringType() ){
+ out<<"$w";
+ }else if( StringType *t=ty->stringType() ){
+ out<<"$";
+ }else if( ArrayType *t=ty->arrayType() ){
+ out<<t->element_type<<'['<<string(t->dims-1,',')<<']';
+ }else if( ObjectType *t=ty->objectType() ){
+ if( t->ident=="<unknown>" ) fail( "export of unknown type" );
+ string id=t->ident;
+ ClassType *ty=t->objectClass();
+ while( ty->attrs & ClassType::PRIVATE ){
+ id=ty->super_name;
+ ty=ty->superClass();
+ }
+ out<<':'<<id;
+ }else if( ObjectType *t=ty->exObjectType() ){
+ if( t->ident=="<unknown>" ) fail( "export of unknown type" );
+ out<<':'<<t->ident;
+ }else if( FunType *t=ty->funType() ){
+ out<<t->return_type<<'(';
+ for( int k=0;k<t->args.size();++k ){
+ if( k ) out<<',';
+ out<<t->args[k];
+ }
+ out<<')';
+ if( t->attrs & FunType::ABSTRACT ) out<<'A';
+ if( t->attrs & FunType::FINAL ) out<<'F';
+ if( t->call_conv==CG_STDCALL ) out<<'S';
+ }else if( ClassType *t=ty->classType() ){
+ out<<'^';
+ if( t->super_name.size() ) out<<t->super_name; else out<<"Null";
+ out<<"{\n";
+ int k;
+ for( k=0;k<t->decls.size();++k ){
+ Decl *d=t->decls[k];
+ if( t->methods.find(d->ident) || t->fields.find(d->ident) ) continue;
+ out<<d<<'\n';
+ }
+ for( k=0;k<t->fields.size();++k ){
+ out<<'.'<<t->fields[k]<<'\n';
+ }
+ for( k=0;k<t->methods.size();++k ){
+ FunType *ty=t->methods[k]->val->type->funType();
+ out<<(ty->method() ? '-' : '+')<<t->methods[k]<<'\n';
+ }
+ out<<"}";
+ if( t->attrs & ClassType::ABSTRACT ) out<<'A';
+ if( t->attrs & ClassType::FINAL ) out<<'F';
+ if( t->attrs & ClassType::EXTERN ) out<<'E';
+ }else{
+ fail( "Export Type '%s' failed",ty->toString().c_str() );
+ }
+ return out;
+}
+
+ostream &out::operator<<( ostream &out,Decl *d ){
+ Val *v=d->val;
+ out<<d->ident<<v->type;
+ if( v->cg_exp ){
+ if( v->type->stringType() && v->constant() ){
+ out<<"=$\""<<tostring( escapeString( v->stringValue() ) )<<'\"';
+ }else{
+ out<<'='<<v->cg_exp;
+ }
+ }
+ return out;
+}
+
+ostream &out::operator<<( ostream &out,const DeclSeq &seq ){
+ int k;
+ for( k=0;k<seq.size();++k ){
+ out<<seq[k]<<'\n';
+ }
+ return out;
+}
\ No newline at end of file
--- /dev/null
+
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+#include "decl.h"
+
+namespace out{
+ostream &operator<<( ostream &out,CGExp *exp );
+ostream &operator<<( ostream &out,Type *type );
+ostream &operator<<( ostream &out,Decl *decl );
+ostream &operator<<( ostream &out,const DeclSeq &seq );
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "std.h"
+#include "parser.h"
+#include "config.h"
+
+static const double PI=3.1415926535897932384626433832795;
+
+using namespace CG;
+
+void Parser::fail( const char *fmt,... ){
+ char buf[256];
+ va_list args;
+ va_start( args,fmt );
+ vsprintf( buf,fmt,args );
+ source_info=toker->sourceInfo();
+ ::fail( buf );
+}
+
+int Parser::curr(){
+ return toker->curr();
+}
+
+int Parser::next(){
+ return toker->next();
+}
+
+string Parser::text(){
+ return toker->text();
+}
+
+bstring Parser::wtext(){
+ if( toker->curr()==T_STRINGCONST ) return unescapeString( toker->wtext() );
+ return toker->wtext();
+}
+
+void Parser::exp( int n ){
+ fail( "Expecting %s but encountered %s",Toker::toString(n).c_str(),Toker::toString(curr()).c_str() );
+}
+
+void Parser::exp( string t ){
+ fail( "Expecting %s but encountered %s",t.c_str(),Toker::toString(curr()).c_str() );
+}
+
+string Parser::parse( int n ){
+ if( curr()!=n ) exp(n);
+ string t=text();
+ next();return t;
+}
+
+bool Parser::cparse( int n ){
+ if( curr()!=n ) return false;
+ next();return true;
+}
+
+bool Parser::pub(){
+ return pub_ && block==mainFun;
+}
+
+void Parser::emitDebugInfo(){
+ if( !block->debug_on ) return;
+ DebugInfoStm *t=new DebugInfoStm;
+ t->source_info=source_info;
+ block->emit(t);
+}
+
+void Parser::emit( Stm *t,bool debugInfo ){
+ if( debugInfo ) emitDebugInfo();
+ t->source_info=source_info;
+ block->emit(t);
+}
+
+void Parser::decl( Decl *d ){
+ block->decl(d);
+ if( pub() ) publish( d );
+}
+
+Type *Parser::parseLitType( Type *ty ){
+ switch( curr() ){
+ case '%':next();return cparse('%') ? Type::int64 : Type::int32;
+ case '#':next();return cparse('#') ? Type::float64 : Type::float32;
+ case '!':next();return Type::float64;
+ case ':':next();break;
+ default:return ty;
+ }
+ switch( curr() ){
+ case T_BYTE:next();return Type::int8;
+ case T_SHORT:next();return Type::int16;
+ case T_INT:next();return Type::int32;
+ case T_LONG:next();return Type::int64;
+ case T_FLOAT:next();return Type::float32;
+ case T_DOUBLE:next();return Type::float64;
+ }
+ fail( "Expecting literal type" );
+ return 0;
+}
+
+Val *Parser::parseLitVal(){
+ Val *v;
+ Type *ty;
+ switch( curr() ){
+ case T_INTCONST:
+ v=new Val( toint(text()) );
+ ty=Type::int32;
+ break;
+ case T_FLOATCONST:
+ v=new Val( tofloat(text()) );
+ ty=Type::float32;
+ break;
+ default:
+ exp( "integer or floating point literal value" );
+ }
+ next();
+ ty=parseLitType( ty );
+ return v->cast( ty );
+}
+
+CGExp *Parser::parseLitExp( Type *ty ){
+ int sign=0;
+ for(;;){
+ if( cparse('+') ){
+ }else if( cparse('-') ){
+ sign=sign ? -sign : -1;
+ }else{
+ break;
+ }
+ }
+ Val *v;
+ switch( curr() ){
+ case T_INTCONST:{
+ int64 n=toint(text());
+ if( sign<0 ) n=-n;
+ v=new Val( n );
+ next();
+ break;
+ }
+ case T_FLOATCONST:{
+ double n=tofloat(text());
+ if( sign<0 ) n=-n;
+ v=new Val( n );
+ next();
+ break;
+ }
+ case T_STRINGCONST:{
+ if( sign ) exp( "Numeric or string literal value" );
+ v=new Val( parseBString() );
+ break;
+ }
+ default:
+ exp( "Numeric or string literal value" );
+ }
+ ty=parseLitType( ty );
+ v=v->cast( ty );
+ return v->cg_exp;
+}
+
+string Parser::parseString(){
+ string t=parse(T_STRINGCONST);
+ return t.substr(1,t.size()-2);
+}
+
+bstring Parser::parseBString(){
+ if( curr()!=T_STRINGCONST ) exp(T_STRINGCONST);
+ bstring t=wtext();next();
+ return t.substr(1,t.size()-2);
+}
+
+string Parser::parseIdent(){
+ if( !import_nest ) return parse(T_IDENT);
+ switch( curr() ){
+ case T_OBJECT:case T_STRING:case T_NEW:case T_DELETE:case T_IDENT:
+ break;
+ default:
+ fail( "Invalid import identifier: %s",Toker::toString(curr()).c_str() );
+ }
+ string id=text();
+ next();
+ return id;
+}
+
+string Parser::parseClassName(){
+ string id=parseIdent();
+ while( cparse('.') ) id+='.'+parseIdent();
+ return id;
+}
+
+string Parser::parseModuleName(){
+ string id=parseIdent();
+ while( cparse('.') ) id+='.'+parseIdent();
+ return tolower(id);
+}
+
+static void ass( bool t ){
+ if( !t ) fail( "Error in import file" );
+}
+
+CGExp *Parser::parseCGExp(){
+
+ int sgn=1;
+ if( cparse('-') ) sgn=-1;
+
+ if( curr()==T_INTCONST || curr()==T_FLOATCONST ){
+ Val *v=parseLitVal();
+ CGLit *t=v->cg_exp->lit();
+ if( t->type==CG_INT64 ) return lit( sgn * t->int_value );
+ if( t->type==CG_FLOAT64 ) return lit( sgn * t->float_value );
+ if( t->type==CG_INT32 ) return lit( sgn * int(t->int_value ) );
+ if( t->type==CG_FLOAT32 ) return lit( sgn * float(t->float_value) );
+ assert(0);
+ }else if( curr()==T_STRINGCONST ){
+ return sym(parseString(),CG_IMPORT);
+ }else if( cparse('$') ){
+ return (new Val(parseBString()))->cg_exp;
+ }
+
+ string id=parseIdent();
+
+ if( id=="nan" ){
+ double zero=0.0;
+ if( cparse('#') ) return lit( float(0.0/zero) );
+ if( cparse('!') ) return lit( double(0.0/zero) );
+ fail( "Nan error" );
+ }
+ if( id=="inf" ){
+ double zero=0.0;
+ if( cparse('#') ) return lit( float(sgn/zero) );
+ if( cparse('!') ) return lit( double(sgn/zero) );
+ fail( "Inf error" );
+ }
+
+ int ty=CG_INT32;
+ if( cparse(':') ){
+ string t=parseIdent();
+ switch(t[0]){
+ case 'b':ty=CG_INT8;break;
+ case 's':ty=CG_INT16;break;
+ case 'i':ty=CG_INT32;break;
+ case 'l':ty=CG_INT64;break;
+ case 'p':ty=CG_PTR;break;
+ case 'f':ty=CG_FLOAT32;break;
+ case 'd':ty=CG_FLOAT64;break;
+ default:fail( "Unrecognized intermediate code data type" );
+ }
+ }
+
+ parse('(');
+ CGExp *exp=0;
+
+ if( id=="mem" ){
+ exp=parseCGExp();
+ int n=0;
+ if( curr()!=')' ){
+ parse(',');
+ n=parseLitVal()->cg_exp->lit()->int_value;
+ }
+ exp=CG::mem(ty,exp,n);
+ }else{
+ fail( "Unrecognized intermediate code expression" );
+ }
+
+ parse(')');
+ return exp;
+}
+
+Decl *Parser::parseImportDecl(){
+ string id=parseIdent();
+ Type *ty=parseType();
+ CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0;
+ return new Decl( id,ty,cg );
+}
+
+int Parser::parseCallConv(){
+
+ if( curr()!=T_STRINGCONST ) return default_call_conv;
+
+ string t=tolower(parseString());
+
+ if( t=="c" ) return CG_CDECL;
+ if( t=="blitz" ) return CG_CDECL;
+ if( t=="os" ) t=env_platform;
+ if( t=="macos" ) return CG_CDECL;
+ if( t=="linux" ) return CG_CDECL;
+ if( t=="win32" ) return CG_STDCALL;
+
+ fail( "Unrecognized calling convention '%s'",t.c_str() );
+ return 0;
+}
+
+void Parser::parseExtern(){
+ next();
+
+ ++extern_nest;
+
+ int call_conv=default_call_conv;
+ default_call_conv=parseCallConv();
+
+ while( !cparse(T_ENDEXTERN) ){
+ source_info=toker->sourceInfo();
+ if( cparse('\n') ){
+ }else if( curr()==T_CONST ){
+ parseConstDecls();
+ }else if( cparse(T_GLOBAL) ){
+ do{
+ string id=parseIdent();
+ Type *ty=parseRefType();
+ CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0;
+ emit( new ExternDeclStm(T_GLOBAL,id,ty,cg,pub()),false );
+ }while( cparse(',') );
+ }else if( cparse(T_FUNCTION) ){
+ do{
+ string id=parseIdent();
+ ExpSeq *defs=new ExpSeq();
+ fun_defaults=defs;
+ FunType *ty=parseType()->funType();
+ fun_defaults=0;
+ if( !ty ) exp( "function type" );
+ CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0;
+ Decl *d=new FunDecl( id,ty,cg,block,defs );
+ decl(d);
+ }while( cparse(',') );
+ }else if( cparse(T_TYPE) ){
+ string id=parseIdent(),super_id;
+ if( cparse(T_EXTENDS) ) super_id=parseIdent();
+ ClassType *class_ty=new ClassType( super_id,block,ClassType::EXTERN );
+ while( !cparse(T_ENDTYPE) ){
+ if( cparse('\n') ){
+ }else if( cparse(T_FIELD) ){
+ do{
+ string id=parseIdent();
+ Type *ty=parseRefType();
+ class_ty->fields.push_back( new Decl(id,ty,0) );
+ }while( cparse(',') );
+ }else if( cparse(T_METHOD) ){
+ string id=parseIdent();
+ ExpSeq *defs=new ExpSeq();
+ fun_defaults=defs;
+ FunType *ty=parseType()->funType();
+ fun_defaults=0;
+ if( !ty ) exp( "method type" );
+ ty->attrs|=FunType::METHOD;
+ CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0;
+ Decl *d=new FunDecl( id,ty,cg,block,defs );
+ class_ty->methods.push_back( d );
+/*
+ string id=parseIdent();
+ FunType *ty=parseType()->funType();
+ if( !ty ) exp( "method type" );
+ ty->attrs|=FunType::METHOD;
+ class_ty->methods.push_back( new Decl(id,ty,0) );
+*/
+ }else{
+ exp( "field or method declaration" );
+ }
+ }
+ decl( new Decl(id,class_ty,lit0) );
+ }else{
+ fail( "Syntax error in extern block - expecting Const, Global, Function or Type declaration" );
+ }
+ }
+ default_call_conv=call_conv;
+
+ --extern_nest;
+}
+
+Type *Parser::parseBaseType(){
+ Scope *scope=block;
+
+ if( import_module ) scope=import_module;
+
+ switch( curr() ){
+ case '!':next();return Type::float64;
+ case '$':next();return Type::stringObject;
+ case '@':if( next()!='@' ) return Type::int8;
+ next();return Type::int16;
+ case '%':if( next()!='%' ) return Type::int32;
+ next();return Type::int64;
+ case '#':if( next()!='#' ) return Type::float32;
+ next();return Type::float64;
+ case T_CSTRING:
+ next();return Type::c_string;
+ case T_WSTRING:
+ next();return Type::w_string;
+ case ':':
+ switch( next() ){
+ case T_BYTE:next();return Type::int8;
+ case T_SHORT:next();return Type::int16;
+ case T_INT:next();return Type::int32;
+ case T_LONG:next();return Type::int64;
+ case T_FLOAT:next();return Type::float32;
+ case T_DOUBLE:next();return Type::float64;
+ case T_OBJECT:next();return Type::objectObject;
+ case T_STRING:next();return Type::stringObject;
+ case T_IDENT:return new ObjectType( parseClassName(),scope );
+ }
+ exp(T_IDENT);
+ case '^':
+ if( import_nest ){
+ next();
+ string super_name=cparse(T_NULL) ? "" : parseClassName();
+ parse('{');
+
+ ClassType *ty=new ClassType( super_name,scope );
+
+ while( !cparse('}') ){
+ if( cparse('\n') ){
+ }else if( curr()=='+' || curr()=='-' ){
+ int tok=curr();next();
+ Decl *d=parseImportDecl();
+ FunType *f=d->val->type->funType();ass( !!f );
+ if( tok=='-' ) f->attrs|=FunType::METHOD;
+ ty->methods.push_back(d);
+ }else if( cparse('.') ){
+ Decl *d=parseImportDecl();
+ ass( !d->val->cg_exp );
+ ty->fields.push_back(d);
+ }else{
+ Decl *d=parseImportDecl();
+ ass( !!d->val->cg_exp );
+ ty->decls.push_back(d);
+ }
+ }
+ if( curr()==T_IDENT ){
+ string id=tolower(parseIdent());
+ if( id.find('a')!=string::npos ) ty->attrs|=ClassType::ABSTRACT;
+ if( id.find('f')!=string::npos ) ty->attrs|=ClassType::FINAL;
+ if( id.find('e')!=string::npos ) ty->attrs|=ClassType::EXTERN;
+ }
+ return ty;
+ }
+ break;
+ }
+ return Type::int32;
+}
+
+FunType *Parser::parseFunType( Type *ty ){
+
+ parse('(');
+
+ FunType *fun=new FunType(ty);
+ fun->call_conv=default_call_conv;
+
+ if( !cparse(')') ){
+ do{
+ CGExp *cg=0;
+
+ string id=parseIdent();
+
+ ExpSeq *tmp_defaults=fun_defaults;
+ fun_defaults=0;
+ Type *ty=parseType();
+ fun_defaults=tmp_defaults;
+
+ if( cparse(T_VAR) ) ty=new VarType(ty);
+
+ if( fun_defaults ){
+ if( cparse(T_EQ) ) fun_defaults->push_back( parseExp() );
+ else fun_defaults->push_back(0);
+ }else if( cparse(T_EQ) ){
+ if( !import_nest ){
+ fail( "Function argument defaults can only be specified in function declaration" );
+// cg=parseLitExp( ty );
+ }else{
+ cg=parseCGExp();
+ }
+ }
+ fun->args.push_back( new Decl(id,ty,cg) );
+ }while( cparse(',') );
+ parse(')');
+ }
+ if( import_nest ){
+ if( curr()==T_IDENT ){
+ string id=tolower(parseIdent());
+ if( id.find('a')!=string::npos ) fun->attrs|=FunType::ABSTRACT;
+ if( id.find('f')!=string::npos ) fun->attrs|=FunType::FINAL;
+ if( id.find('s')!=string::npos ) fun->call_conv=CG_STDCALL;
+ }
+ }else if( curr()==T_STRINGCONST ){
+ fun->call_conv=parseCallConv();
+ }
+ return fun;
+}
+
+int Parser::arrayDeclDims( string t ){
+ assert( t.size()>1 && t[0]=='[' && t[t.size()-1]==']' );
+ int n=1;
+ for( int i=1;i<t.size()-1;++i ){
+ if( t[i]==',' ) ++n;
+ }
+ return n;
+}
+
+Type *Parser::parseType(){
+
+ Type *ty;
+
+ if( strictMode>1 && !import_nest ){
+ FunType *fun;
+ switch( curr() ){
+ case '(':
+ fun=parseFunType( Type::int32 );
+ fun->attrs|=FunType::VOIDFUN;
+ ty=fun;
+ break;
+ case '%':case ':':
+ ty=parseBaseType();
+ break;
+ default:
+ ty=parseBaseType();
+ if( ty==Type::int32 ) fail( "Missing type specifier" );
+ }
+ }else{
+ ty=parseBaseType();
+ }
+
+ for(;;){
+ if( curr()=='(' ){
+ if( fun_defaults ){
+ for( int i=0;i<fun_defaults->size();++i ){
+ if( (*fun_defaults)[i] ){
+ fail( "Illegal default function parameter" );
+ }
+ }
+ fun_defaults->clear();
+ }
+ ty=parseFunType(ty);
+ continue;
+ }
+
+ if( ty->cstringType() || ty->wstringType() ) break;
+
+ if( curr()==T_ARRAYDECL ){
+ if( !import_nest ) ty=new RefType(ty);
+ ArrayType *arr=new ArrayType( ty,arrayDeclDims( text() ) );//text().size()-1 );
+ next();
+ ty=arr;
+ }else if( import_nest && cparse('&') ){
+ ty=new RefType(ty);
+ }else if( import_nest && cparse('*') ){
+ ty=new PtrType(ty);
+ }else if( cparse(T_PTR) ){
+ ty=new PtrType( ty );
+ }else{
+ break;
+ }
+ }
+ return ty;
+}
+
+RefType *Parser::parseRefType(){
+ Type *ty=parseType();
+ if( ty->cstringType() || ty->wstringType() ) fail( "Illegal variable type" );
+ return new RefType( ty );
+}
+
+Exp *Parser::parseCastExp( Type *ty ){
+ for(;;){
+ if( curr()==T_ARRAYDECL ){
+ ty=new ArrayType( new RefType( ty ),arrayDeclDims( text() ) );
+ next();
+ }else if( cparse(T_PTR) ){
+ ty=new PtrType(ty);
+ }else{
+ break;
+ }
+ }
+ if( curr()=='(' ){
+ return parsePostExp( new CastExp( ty,parsePriExp() ) );
+ }
+ return new CastExp( ty,parsePreExp() );
+}
+
+Exp *Parser::parseIdentExp(){
+ string id=parseIdent();
+ Type *ty=0;
+ switch( curr() ){
+ case '@':case '%':case '#':case '!':case '$':case ':':ty=parseBaseType();break;
+ }
+ return new IdentExp(id,ty);
+}
+
+ArrayExp *Parser::parseArrayExp( Type *ty ){
+ parse('[');
+ ArrayExp *exp=new ArrayExp(ty);
+ do{
+ exp->dims.push_back( parseExp() );
+ }while(cparse(','));
+ parse(']');
+ return exp;
+}
+
+Exp *Parser::parseArrayDataExp(){
+ parse('[');
+ if( cparse(']') ) return new NullExp();
+ ArrayDataExp *e=new ArrayDataExp();
+ do{
+ e->exps.push_back( parseExp() );
+ }while( cparse(',') );
+ parse(']');
+ return e;
+}
+
+Exp *Parser::parseNewExp(){
+ Type *t=0;
+ switch( curr() ){
+ case T_BYTE:t=Type::int8;break;
+ case T_SHORT:t=Type::int16;break;
+ case T_INT:t=Type::int32;break;
+ case T_LONG:t=Type::int64;break;
+ case T_FLOAT:t=Type::float32;break;
+ case T_DOUBLE:t=Type::float64;break;
+ case T_STRING:t=Type::stringObject;break;
+ case T_OBJECT:t=Type::objectObject;break;
+ }
+ if( t ){
+ next();
+ }else{
+ Exp *e=parsePriExp();
+ if( curr()!=T_ARRAYDECL && curr()!=T_PTR && curr()!='[' ){
+ return new NewExp(e);
+ }
+ IdentExp *id=dynamic_cast<IdentExp*>(e);
+ if( !id ) fail( "Expecting element type" );
+ t=new ObjectType( id->ident,block );
+ }
+ for(;;){
+ if( curr()==T_ARRAYDECL ){
+ t=new ArrayType( t,arrayDeclDims( text() ) );
+ next();
+ }else if( cparse(T_PTR) ){
+ t=new PtrType( t );
+ }else{
+ break;
+ }
+ }
+ parse('[');
+ ArrayExp *exp=new ArrayExp(t);
+ do{
+ exp->dims.push_back( parseExp() );
+ }while(cparse(','));
+ parse(']');
+ return exp;
+}
+
+Exp *Parser::parsePriExp(){
+
+ int t;
+ Type *ty;
+ Exp *e=0,*lhs,*rhs;
+
+ //Yuck! This extremely nasty hack allows for 'bracketless' fun invocation by statements...
+ if( primary ){
+ e=primary;
+ primary=0;
+ return e;
+ }
+
+ switch( int op=curr() ){
+ case '(':
+ next();
+ e=parseExp();
+ parse(')');
+ return e;
+ case '[':
+ return parseArrayDataExp();
+ case T_IDENT:
+ return parseIdentExp();
+ case T_INTCONST:case T_FLOATCONST:
+ return new ValExp( parseLitVal() );
+ case T_STRINGCONST:
+ return new ValExp( new Val(parseBString()) );
+ case T_TRUE:
+ next();return new ValExp( new Val(1) );
+ case T_FALSE:
+ next();return new ValExp( new Val(0) );
+ case T_PI:
+ next();return new ValExp( new Val((double)PI) );
+ case T_NULL:
+ next();return new NullExp();
+ case T_SELF:
+ next();return new SelfExp();
+ case T_SUPER:
+ next();return new SuperExp();
+ case T_NEW:
+ next();return parseNewExp();
+ case T_LEN:
+ case T_CHR:
+ case T_ASC:
+ case T_INCBINPTR:
+ case T_INCBINLEN:
+ ty=0;
+ switch( next() ){
+ case '@':case '%':case '#':case '!':case '$':case ':':
+ if( op!=T_VARPTR ) ty=parseBaseType();
+ break;
+ }
+ return new IntrinsicExp( op,ty,parsePriExp() );
+ case '.':
+ next();return new GlobalExp( parseIdent() );
+ case T_MIN:case T_MAX:
+ t=curr();next();
+ parse('(');lhs=parseExp();parse(',');rhs=parseExp();parse(')');
+ return new ArithExp( t,lhs,rhs );
+ }
+ exp( "expression" );
+ return 0;
+}
+
+Exp *Parser::parsePostExp( Exp *t ){
+ if( !t ) t=parsePriExp();
+ for(;;){
+ if( cparse('.') ){
+ t=new MemberExp( t,parsePriExp() );
+ }else if( cparse('(') ){
+ InvokeExp *i=new InvokeExp(t);
+ if( !cparse(')') ){
+ do{
+ if( curr()==',' ) i->seq.push_back(0);
+ else i->seq.push_back(parseExp());
+ }while( cparse(',') );
+ parse(')');
+ }
+ t=i;
+ }else if( cparse('[') ){
+ int c=curr();
+ if( c==T_DOTDOT ){
+ if( next()==']' ) t=new SliceExp(c,t,0,0);
+ else t=new SliceExp(c,t,0,parseExp());
+ }else{
+ Exp *e=parseExp();
+ int c=curr();
+ if( c==T_DOTDOT ){
+ if( next()==']' ) t=new SliceExp(c,t,e,0);
+ else t=new SliceExp(c,t,e,parseExp());
+ }else{
+ IndexExp *i=new IndexExp(t);
+ i->seq.push_back(e);
+ while( cparse(',') ) i->seq.push_back(parseExp());
+ t=i;
+ }
+ }
+ parse(']');
+ }else if( curr()==T_ARRAYDECL || curr()==T_PTR ){
+ IdentExp *e=dynamic_cast<IdentExp*>(t);
+ if( !e ) fail( "Expecting identifier" );
+ ObjectType *ty=new ObjectType( e->ident,block );
+ t=parseCastExp(ty);
+ }else{
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parsePreExp(){
+ Type *ty;
+ if( primary ) return parsePostExp();
+ switch( int op=curr() ){
+ case T_NOT:
+ next();return new NotExp( parsePreExp() );
+ case '-':case '+':case '~':case T_ABS:case T_SGN:
+ next();return new UnaryExp( op,parsePreExp() );
+ case T_SIZEOF:
+ case T_VARPTR:
+ ty=0;
+ switch( next() ){
+ case '@':case '%':case '#':case '!':case '$':case ':':
+ if( op!=T_VARPTR ) ty=parseBaseType();
+ break;
+ }
+ return new IntrinsicExp( op,ty,parsePostExp() );
+ case T_BYTE:
+ next();return parseCastExp( Type::int8 );
+ case T_SHORT:
+ next();return parseCastExp( Type::int16 );
+ case T_INT:
+ next();return parseCastExp( Type::int32 );
+ case T_LONG:
+ next();return parseCastExp( Type::int64 );
+ case T_FLOAT:
+ next();return parseCastExp( Type::float32 );
+ case T_DOUBLE:
+ next();return parseCastExp( Type::float64 );
+ case T_STRING:
+ if( next()=='.' ) return parsePostExp( new ValExp(Type::stringClass) );
+ return parseCastExp( Type::stringObject );
+ case T_OBJECT:
+ if( next()=='.' ) return parsePostExp( new ValExp(Type::objectClass) );
+ return parseCastExp( Type::objectObject );
+ }
+
+ return parsePostExp();
+}
+
+Exp *Parser::parsePowExp(){
+ Exp *t=parsePreExp();
+ for(;;){
+ switch( int op=curr() ){
+ case '^':
+ next();
+ t=new ArithExp( op,t,parsePreExp() );
+ break;
+ default:
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parseFactExp(){
+ Exp *t=parsePowExp();
+ for(;;){
+ switch( int op=curr() ){
+ case '*':case '/':case T_MOD:
+ next();
+ t=new ArithExp( op,t,parsePowExp() );
+ break;
+ case T_SHL:case T_SHR:case T_SAR:
+ next();
+ t=new BitwiseExp( op,t,parsePowExp() );
+ break;
+ default:
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parseTermExp(){
+ Exp *t=parseFactExp();
+ for(;;){
+ switch( int op=curr() ){
+ case '+':case '-':
+ next();
+ t=new ArithExp( op,t,parseFactExp() );
+ break;
+ default:
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parseBitwiseExp(){
+ Exp *t=parseTermExp();
+ for(;;){
+ switch( int op=curr() ){
+ case '&':case '|':case '~':
+ next();
+ t=new BitwiseExp( op,t,parseTermExp() );
+ break;
+ default:
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parseCmpExp(){
+ Exp *t=parseBitwiseExp();
+ for(;;){
+ switch( int op=curr() ){
+ case T_LT:case T_EQ:case T_GT:case T_LE:case T_GE:case T_NE:
+ next();
+ t=new CmpExp( op,t,parseBitwiseExp() );
+ break;
+ default:
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parseShortCircExp(){
+ Exp *t=parseCmpExp();
+ for(;;){
+ switch( int op=curr() ){
+ case T_AND:case T_OR:
+ next();
+ t=new ShortCircExp( op,t,parseCmpExp() );
+ break;
+ default:
+ return t;
+ }
+ }
+}
+
+Exp *Parser::parseExp(){
+ Exp *e=parseShortCircExp();
+ return e;
+}
+
+string Parser::parseMetaData(){
+ if( !cparse('{') ) return "";
+
+ string meta;
+
+ while( curr()==T_IDENT ){
+ string id=parseIdent(),t;
+ if( cparse( T_EQ ) ){
+ switch( curr() ){
+ case T_INTCONST:
+ case T_FLOATCONST:
+ case T_STRINGCONST:
+ t=text();
+ next();
+ break;
+ default:
+ fail( "Meta data must be literal constant" );
+ }
+ }else{
+ t="1";
+ }
+ if( meta.size() ) meta+=" ";
+ meta+=id+"="+t;
+ }
+
+ parse( '}' );
+ return meta;
+}
+
+void Parser::addMetaData( const vector<Decl*> &decls ){
+ string meta=parseMetaData();
+ for( vector<Decl*>::const_iterator it=decls.begin();it!=decls.end();++it ){
+ (*it)->setMetaData( meta );
+ }
+}
+
+Decl *Parser::parseInitDecl( Exp **init ){
+ string id=parseIdent();
+ Type *ty=parseRefType();
+ Exp *_init=0;
+ if( cparse(T_EQ) ){
+ _init=parseExp();
+ }else if( cparse('[') ){
+ ArrayExp *exp=new ArrayExp(ty);
+ do{
+ exp->dims.push_back( parseExp() );
+ }while( cparse(',') );
+ parse(']');
+ ty=new RefType( new ArrayType(ty,exp->dims.size()) );
+ _init=exp;
+ }else{
+ _init=new NullExp();
+ }
+ *init=_init;
+ return new Decl( id,ty,0 );
+}
+
+void Parser::parseLocalDecls(){
+ next();
+ emitDebugInfo();
+
+ vector<Decl*> decls;
+
+ do{
+ Exp *e;
+ Decl *d=parseInitDecl( &e );
+ decls.push_back( d );
+ emit( new LocalDeclStm(d->ident,d->val->type,e),false );
+ }while( cparse(',') );
+
+ addMetaData( decls );
+}
+
+void Parser::parseGlobalDecls(){
+ next();
+ emitDebugInfo();
+
+ vector<Decl*> decls;
+
+ do{
+ Exp *e;
+ Decl *d=parseInitDecl( &e );
+ decls.push_back( d );
+ emit( new GlobalDeclStm(d->ident,d->val->type,e,pub()),false );
+ }while( cparse(',') );
+
+ addMetaData( decls );
+}
+
+void Parser::parseConstDecls(){
+ next();
+
+ vector<Decl*> decls;
+
+ do{
+ string id=parseIdent();
+ Type *ty=parseType();
+ if( !cparse(T_EQ) ) fail( "Constants must be initialized" );
+ Decl *d=new ConstDecl( id,ty,block,parseExp() );
+ decls.push_back( d );
+ decl( d );
+ }while( cparse(',') );
+
+ addMetaData( decls );
+}
+
+void Parser::parseTypeDecl(){
+ next();
+
+ string id=parseIdent();
+ string super_name=cparse(T_EXTENDS) ? parseClassName() : "Object";
+
+ int attrs=0;
+ if( cparse(T_FINAL) ){
+ attrs=ClassType::FINAL;
+ }else if( cparse(T_ABSTRACT) ){
+ attrs=ClassType::ABSTRACT;
+ }
+
+ string meta=parseMetaData();
+
+ if( !pub() ) attrs|=ClassType::PRIVATE;
+
+ ClassType *class_type=new ClassType( super_name,block,attrs );
+
+ ClassBlock *class_block=new ClassBlock( block,id,class_type );
+
+ class_block->class_decl->setMetaData( meta );
+
+ block=class_block;
+ while( !cparse(T_ENDTYPE) ){
+ source_info=toker->sourceInfo();
+ switch( curr() ){
+ case '\n':case ';':next();break;
+ case T_FIELD:parseFieldDecls();break;
+ case T_CONST:parseConstDecls();break;
+ case T_GLOBAL:parseGlobalDecls();break;
+ case T_METHOD:parseFunDecl( FunType::METHOD );break;
+ case T_FUNCTION:parseFunDecl( 0 );break;
+ default:fail( "Syntax error in user defined type declaration" );
+ }
+ }
+ block=block->outer;
+
+}
+
+void Parser::parseFieldDecls(){
+ next();
+
+ ClassBlock *class_block=dynamic_cast<ClassBlock*>(block);
+ if( !class_block ) fail( "Field declarations must appear within a Type declaration" );
+ ClassType *class_type=class_block->type;
+
+ Block *t_block=block;
+ block=class_block->field_ctors;
+
+ emitDebugInfo();
+
+ vector<Decl*> decls;
+
+ do{
+ Exp *e;
+ Decl *d=parseInitDecl( &e );
+ emit( new FieldDeclStm(d->ident,d->val->type,e),false );
+ class_type->fields.push_back( d );
+ decls.push_back( d );
+ }while( cparse(',') );
+
+ addMetaData( decls );
+
+ block=t_block;
+}
+
+void Parser::parseFunDecl( int attrs ){
+ next();
+
+ bool method=!!(attrs & FunType::METHOD);
+
+ ClassBlock *class_block=dynamic_cast<ClassBlock*>(block);
+ ClassType *class_type=class_block ? class_block->type : 0;
+
+ if( method && !class_block ) fail( "Methods must appear within a type" );
+
+ string id;
+ Block *fun_block=0;
+
+ if( cparse(T_NEW) ){
+ id="New";
+ if( !method ) fail( "New must be a method" );
+
+ fun_block=class_block->ctor_new;
+ if( !fun_block ) fail( "New method already defined" );
+
+ class_block->ctor_new=0;
+ }else if( cparse(T_DELETE) ){
+ id="Delete";
+ if( !method ) fail( "Delete must be a method" );
+
+ class_block->makeDtor();
+
+ fun_block=class_block->dtor_delete;
+ if( !fun_block ) fail( "Delete method already defined" );
+
+ class_block->dtor_delete=0;
+ }else{
+ id=parseIdent();
+ }
+
+ ExpSeq *defs=new ExpSeq();
+ fun_defaults=defs;
+ FunType *ty=parseType()->funType();
+ fun_defaults=0;
+
+ if( !ty ) fail( "Expecting function type" );
+
+ if( ty->return_type->cstringType() || ty->return_type->wstringType() ) fail( "Illegal function return type" );
+
+ int i;
+ for( i=0;i<ty->args.size();++i ){
+ Type *t=ty->args[i]->val->type;
+ if( t->cstringType() || t->wstringType() ) fail( "Illegal function parameter type" );
+ }
+
+ bool noDebug=false;
+
+ if( cparse( T_NODEBUG ) ) noDebug=true;
+
+ if( cparse( T_FINAL ) ){
+ if( !class_block ){
+ fail( "Final cannot be used with global functions" );
+ }
+ attrs|=FunType::FINAL;
+ }else if( cparse( T_ABSTRACT ) ){
+ if( !class_block ){
+ fail( "Abstract cannot be used with global functions" );
+ }
+ if( class_type->attrs & ClassType::FINAL ){
+ fail( "Abstract methods cannot appear in final types" );
+ }
+ attrs|=FunType::ABSTRACT;
+ }else if( method && (class_type->attrs & ClassType::FINAL) ){
+ attrs|=FunType::FINAL;
+ }
+
+ if( cparse( T_NODEBUG ) ) noDebug=true;
+
+ ty->attrs|=attrs;
+
+ string meta=parseMetaData();
+
+ if( attrs & FunType::ABSTRACT ){
+ FunDecl *decl=new FunDecl(id,ty,sym("brl_blitz_NullMethodError",CG_IMPORT),block,defs);
+ class_type->methods.push_back( decl );
+ decl->setMetaData( meta );
+ return;
+ }
+
+ if( !fun_block ){
+ bool pub=method || class_block || this->pub();
+ FunBlock *t=new FunBlock( block,id,ty,pub,defs );
+ t->fun_decl->setMetaData( meta );
+ fun_block=t;
+ }
+
+ if( noDebug ) fun_block->debug_on=false;
+
+ parseStms( fun_block,method ? T_ENDMETHOD : T_ENDFUNCTION );
+}
+
+static bool isExpOp( int t ){
+ switch( t ){
+ case '&':case '|':case '~':
+ case '+':case '-':case '*':case '/':case T_MOD:case '^':
+ case T_LT:case T_GT:case T_LE:case T_GE:case T_EQ:case T_NE:
+ case T_AND:case T_OR:case T_SHL:case T_SHR:case T_SAR:
+ return true;
+ }
+ return false;
+}
+
+void Parser::parseExpStm(){
+
+ Exp *e=parsePreExp();
+
+ if( cparse(T_EQ) ){
+ emit( new AssignStm(e,parseExp()),true );
+ return;
+ }
+
+ int op=0;
+ switch( curr() ){
+ case T_ADDASSIGN:case T_SUBASSIGN:case T_MULASSIGN:case T_DIVASSIGN:case T_MODASSIGN:
+ case T_ORASSIGN:case T_ANDASSIGN:case T_XORASSIGN:case T_SHLASSIGN:case T_SHRASSIGN:case T_SARASSIGN:
+ op=curr();next();break;
+ }
+ if( op ){
+ emit( new OpAssignStm(op,e,parseExp()),true );
+ return;
+ }
+
+ if( dynamic_cast<NewExp*>(e) ){
+ emit( new EvalStm(e),true );
+ return;
+ }
+
+ InvokeExp *t=dynamic_cast<InvokeExp*>(e);
+ bool more=false;
+
+ if( !t ){
+ t=new InvokeExp(e);
+ more=curr()!=';' && curr()!='\n' && curr()!=EOF;
+ }else if( t->seq.size()==1 ){
+ if( isExpOp(curr()) ){
+ primary=t->seq[0];
+ t->seq[0]=parseExp();
+ }
+ more=cparse(',');
+ }
+ if( more ){
+ do{
+ if( curr()==',' ) t->seq.push_back(0);
+ else t->seq.push_back( parseExp() );
+ }while( cparse(',') );
+ }
+ emit( new EvalStm(t),true );
+}
+
+void Parser::parseIfStm( int t_term ){
+ source_info=toker->sourceInfo();
+ next();
+
+ Exp *e=parseExp();
+ cparse( T_THEN );
+
+ int term=t_term ? t_term : (curr()=='\n' ? T_ENDIF : '\n');
+
+ IfStm *stm=new IfStm( e,0,0 );
+ emit( stm,true );
+
+ int t;
+ block=stm->then_block=new Block( block );
+ for(;;){
+ t=curr();
+ if( t==term || t==T_ELSE || t==T_ELSEIF ) break;
+ parseStm();
+ }
+ block=block->outer;
+
+ if( t!=term ){
+ block=stm->else_block=new Block( block );
+ if( t==T_ELSE ){
+ if( next()==T_IF ){
+ parseIfStm( term );
+ }else{
+ while( curr()!=term ) parseStm();
+ }
+ }else{
+ //t==T_ELSEIF
+ parseIfStm( term );
+ }
+ block=block->outer;
+ }
+
+ if( !t_term && term==T_ENDIF ) next();
+}
+
+void Parser::parseLoopCtrlStm(){
+ int toke=curr();
+ string lab;
+ if( next()==T_IDENT ) lab=parseIdent();
+ emit( new LoopCtrlStm( toke,lab ),true );
+}
+
+void Parser::parseForStm(){
+ next();
+
+ LoopBlock *loop_block=new LoopBlock( block,loopLabel );
+ loopLabel="";
+
+ Exp *var;
+ if( cparse(T_LOCAL) ){
+ string id=parseIdent();
+ Type *ty=parseRefType();
+ var=new LocalDeclExp( id,ty,loop_block );
+ }else{
+ var=parsePostExp();
+ }
+ if( !cparse(T_EQ) ) exp( "assignment" );
+
+ if( cparse(T_EACHIN) ){
+ Exp *coll=parseExp();
+ emit( new ForEachStm( var,coll,loop_block ),true );
+ parseStms( loop_block,T_NEXT );
+ return;
+ }
+
+ Exp *init=parseExp();
+ bool until;
+ if( cparse(T_TO) ) until=false;
+ else if( cparse(T_UNTIL) ) until=true;
+ else fail( "Expecting 'To' or 'Until'" );
+ Exp *to=parseExp();
+ Exp *step=cparse(T_STEP) ? parseExp() : 0;
+ emit( new ForStm( var,init,to,step,loop_block,until ),true );
+ parseStms( loop_block,T_NEXT );
+}
+
+void Parser::parseWhileStm(){
+ next();
+
+ LoopBlock *loop_block=new LoopBlock( block,loopLabel );
+ loopLabel="";
+
+ emit( new WhileStm( parseExp(),loop_block),true );
+
+ parseStms( loop_block,T_WEND );
+}
+
+void Parser::parseRepeatStm(){
+ next();
+
+ LoopBlock *loop_block=new LoopBlock( block,loopLabel );
+ loopLabel="";
+
+ block=loop_block;
+ while( curr()!=T_UNTIL && curr()!=T_FOREVER ){
+ parseStm();
+ }
+ source_info=toker->sourceInfo();
+ int c=curr();next();
+ block=block->outer;
+
+ Exp *e=(c==T_UNTIL) ? parseExp() : 0;
+
+ emit( new RepeatStm(e,loop_block),true );
+}
+
+void Parser::parseTryStm(){
+ next();
+
+ TryStm *try_stm=new TryStm( new Block(block) );
+ emit( try_stm,true );
+
+ block=try_stm->block;
+ while( curr()!=T_CATCH && curr()!=T_ENDTRY ){
+ parseStm();
+ }
+ block=block->outer;
+
+ while( cparse(T_CATCH) ){
+ TryCatch *t=new TryCatch( new Block(block) );
+ try_stm->catches.push_back( t );
+
+ t->ident=parseIdent();
+ t->type=parseType();
+
+ block=t->block;
+ while( curr()!=T_CATCH && curr()!=T_ENDTRY ){
+ parseStm();
+ }
+ block=block->outer;
+ }
+ parse( T_ENDTRY );
+}
+
+void Parser::parseThrowStm(){
+ next();
+ emit( new ThrowStm(parseExp()),true );
+}
+
+void Parser::parseSelectStm(){
+ next();
+
+ SelectStm *sel=new SelectStm( parseExp() );
+ emit( sel,true );
+
+ while( cparse('\n') ){}
+
+ source_info=toker->sourceInfo();
+ while( cparse(T_CASE) ){
+ SelCase *t_case=new SelCase( new Block( block ) );
+ t_case->source_info=source_info;
+ sel->cases.push_back( t_case );
+
+ do{
+ t_case->exps.push_back( parseExp() );
+ }while( cparse(',') );
+
+ block=t_case->block;
+ while( curr()!=T_CASE && curr()!=T__DEFAULT && curr()!=T_ENDSELECT ){
+ parseStm();
+ }
+ source_info=toker->sourceInfo();
+ block=block->outer;
+ }
+
+ if( cparse(T__DEFAULT) ){
+ sel->_default=new Block( block );
+
+ block=sel->_default;
+ while( curr()!=T_ENDSELECT ){
+ parseStm();
+ }
+ block=block->outer;
+ }
+
+ parse( T_ENDSELECT );
+}
+
+void Parser::parseReturnStm(){
+ next();
+ Exp *exp=0;
+ if( curr()!=';' && curr()!='\n' && curr()!=EOF ) exp=parseExp();
+ emit( new ReturnStm(exp),true );
+}
+
+void Parser::parseDeleteStm(){
+ next();
+ Exp *exp=parseExp();
+ emit( new DeleteStm(exp),true );
+}
+
+void Parser::parseAccess(){
+ switch( curr() ){
+ case T_PUBLIC:pub_=true;break;
+ case T_PRIVATE:pub_=false;break;
+ default:assert(0);
+ }
+ next();
+}
+
+void Parser::parseLabelStm(){
+ next();
+ string id=parseIdent();
+ if( strictMode ){
+ while( cparse('\n') ){}
+ switch( curr() ){
+ case T_FOR:case T_WHILE:case T_REPEAT:case T_DEFDATA:
+ break;
+ default:
+ fail( "Labels must appear before a loop or DefData statement" );
+ }
+ if( curr()!=T_DEFDATA ){
+ loopLabel=id;
+ return;
+ }
+ }
+ if( block->fun_block->labels.count(id) ) fail( "Duplicate label '%s'",id.c_str() );
+ CGSym *goto_sym=CG::sym();
+ CGSym *restore_sym=CG::sym();
+ LabelStm *stm=new LabelStm(goto_sym,restore_sym);
+ block->fun_block->labels.insert( make_pair(tolower(id),stm) );
+ emit( stm,true );
+}
+
+void Parser::parseGotoStm(){
+ next();
+ emit( new GotoStm( parseIdent() ),true );
+}
+
+void Parser::parseAssertStm(){
+ next();
+ Exp *e=parseExp(),*m;
+ if( cparse(',') || cparse(T_ELSE) ) m=parseExp();
+ else m=new ValExp( new Val(tobstring("Assert failed")) );
+ emit( new AssertStm(e,m),true );
+}
+
+void Parser::includeFile( string file ){
+
+ file=realpath(file);
+
+ Toker *t=toker;
+ toker=new Toker( file );
+
+ string cd=getcwd();
+ setcwd( getdir(file) );
+
+ while( curr()!=EOF ){
+ parseStm();
+ }
+ setcwd( cd );
+ toker=t;
+}
+
+void Parser::parseDataStm(){
+ next();
+ DataStm *t=new DataStm();
+ emit( t,false );
+ do{
+ t->exps.push_back( parseExp() );
+ }while( cparse(',') );
+}
+
+void Parser::parseReadStm(){
+ next();
+ ReadStm *t=new ReadStm();
+ emit( t,true );
+ do{
+ t->exps.push_back( parseExp() );
+ }while( cparse(',') );
+}
+
+void Parser::parseRestoreStm(){
+ next();
+ emit( new RestoreStm( parseIdent() ),true );
+}
+
+void Parser::parseStm(){
+ source_info=toker->sourceInfo();
+
+ switch( curr() ){
+ case ';':
+ case '\n':
+ next();
+ break;
+ case '#':
+ parseLabelStm();
+ break;
+ case T_DEFDATA:
+ parseDataStm();
+ break;
+ case T_READDATA:
+ parseReadStm();
+ break;
+ case T_RESTOREDATA:
+ parseRestoreStm();
+ break;
+ case T_GOTO:
+ parseGotoStm();
+ break;
+ case T_TRY:
+ parseTryStm();
+ break;
+ case T_THROW:
+ parseThrowStm();
+ break;
+ case T_IF:
+ //case T_ELSEIF:
+ parseIfStm(0);
+ break;
+ case T_GLOBAL:
+ parseGlobalDecls();
+ break;
+ case T_FUNCTION:
+ parseFunDecl( 0 );
+ break;
+ case T_EXIT:case T_CONTINUE:
+ parseLoopCtrlStm();
+ break;
+ case T_FOR:
+ parseForStm();
+ break;
+ case T_WHILE:
+ parseWhileStm();
+ break;
+ case T_REPEAT:
+ parseRepeatStm();
+ break;
+ case T_SELECT:
+ parseSelectStm();
+ break;
+ case T_RETURN:
+ parseReturnStm();
+ break;
+ case T_ASSERT:
+ parseAssertStm();
+ break;
+ case T_END:
+ next();emit( new EndStm(),true );
+ break;
+ case T_RELEASE:
+ next();emit( new ReleaseStm( parseExp() ),true );
+ break;
+ case T_LOCAL:
+ parseLocalDecls();
+ break;
+ case T_CONST:
+ parseConstDecls();
+ break;
+ case T_TYPE:
+ parseTypeDecl();
+ break;
+ case T_INCLUDE:
+ next();includeFile( parseString() );
+ break;
+ case T_INCBIN:
+ next();emit( new IncbinStm( parseString() ),false );
+ break;
+ case T_EXTERN:
+ parseExtern();
+ break;
+ case T_PUBLIC:case T_PRIVATE:
+ parseAccess();
+ break;
+ case T_MODULE:case T_MODULEINFO:case T_IMPORT:case T_STRICT:
+ fail( "'%s' must appear at top of file",toker->text().c_str() );
+ case T_FIELD:
+ fail( "Field declaration outside of user defined type" );
+ case T_METHOD:
+ fail( "Method declaration outside of user defined type" );
+ case T_ELSE:
+ fail( "'Else' without matching 'If'" );
+ case T_ENDIF:
+ fail( "'%s' without matching 'If'",toker->text().c_str() );
+ case T_NEXT:
+ fail( "'Next' without matching 'For'" );
+ case T_WEND:
+ fail( "'%s' without matching 'While'",toker->text().c_str() );
+ case T_UNTIL:
+ fail( "'Until' without matching 'Repeat'" );
+ case T_FOREVER:
+ fail( "'Forever' without matching 'Repeat'" );
+ case T_CASE:
+ fail( "'Case' without matching 'Select'" );
+ case T__DEFAULT:
+ fail( "'Default' without matching 'Select'" );
+ case T_CATCH:
+ fail( "'Catch' without matching 'Try'" );
+ case T_ENDTRY:
+ fail( "'%s' without matching 'Try'",toker->text().c_str() );
+ case T_ENDTYPE:
+ fail( "'%s' without matching 'Type'",toker->text().c_str() );
+ case T_ENDEXTERN:
+ fail( "'%s' without matching 'Extern'",toker->text().c_str() );
+ case T_ENDMETHOD:
+ fail( "'%s' without matching 'Method'",toker->text().c_str() );
+ case T_ENDFUNCTION:
+ fail( "'%s' without matching 'Function'",toker->text().c_str() );
+ case T_ENDSELECT:
+ fail( "'%s' without matching 'Select'",toker->text().c_str() );
+ default:
+ parseExpStm();
+ }
+}
+
+void Parser::parseStms( Block *t,int term ){
+
+ Block *t_block=block;
+ block=t;
+
+ while( curr()!=term ){
+ parseStm();
+ }
+
+ next();
+ block=t_block;
+}
+
+void Parser::importFile( string file,ModuleType *mod ){
+
+ Toker *t=toker;
+ toker=new Toker( file );
+ ModuleType *m=import_module;
+ import_module=mod;
+
+ ++import_nest;
+
+ while( curr()!=EOF ){
+ source_info=toker->sourceInfo();
+ if( cparse(';') ){
+ }else if( cparse('\n') ){
+ }else if( cparse( T_IMPORT ) ){
+ parseImport();
+ }else if( cparse( T_MODULEINFO ) ){
+ parseString();
+ }else{
+ Decl *d=parseImportDecl();
+ if( import_module ){
+ import_module->decls.push_back(d);
+ }else{
+ mainFun->decl(d);
+ moduleExports.push_back(d);
+ }
+ }
+ }
+
+ --import_nest;
+
+ toker->close();
+ import_module=m;
+ toker=t;
+}
+
+void Parser::importModule( string mod ){
+
+ string mung="@"+mod;
+ if( rootScope.find(mung) ) return;
+
+ vector<string> ids;
+ splitModule( mod,ids );
+
+ ModuleType *mod_ty;
+ DeclSeq *decls=&mainFun->decls;
+
+ int k;
+ for( k=0;k<ids.size();++k ){
+ string id=ids[k];
+ if( Val *v=decls->find(id) ){
+ mod_ty=v->type->moduleType();
+ if( !mod_ty ) fail( "Unable to import module '%s'",mod.c_str() );
+ }else{
+ mod_ty=new ModuleType();
+ decls->push_back( new Decl(id,mod_ty,lit0) );
+ }
+ decls=&mod_ty->decls;
+ }
+
+ rootScope.push_back( new Decl(mung,mod_ty,lit0) );
+
+ importFile( moduleInterface(mod),mod_ty );
+
+ if( !import_module ){
+ string t="import "+mod;
+ if( !import_nest ){
+ objectImports.push_back(t);
+ emit( new ImportStm(sym(mungModuleEntry(mod),CG_IMPORT)),false );
+ }
+ moduleImports.push_back(t);
+ }
+}
+
+void Parser::importSource( string file ){
+
+ string ext=tolower(getext(file)),path=realpath(file);
+
+ if( ext=="bmx" ){
+ if( !importedSources.insert( tolower(path) ).second ) return;
+
+ if( !ftime(path) ) fail( "File '%s' not found",path.c_str() );
+
+ string cd=getcwd();
+ setcwd( getdir(path) );
+
+ importFile( ".bmx/"+stripdir(path)+config_mung+".i",0 );
+
+ setcwd( cd );
+
+ if( !import_nest ){
+ string t="import \""+file+'\"';
+ objectImports.push_back( t );
+ emit( new ImportStm( sym(mungObjectEntry(file),CG_IMPORT) ),false );
+ }
+ }else if( ext=="o" || ext=="a" || ext=="lib" ){
+
+ if( !import_module ){
+
+ if( !ftime(path) ) fail( "File '%s' not found",path.c_str() );
+
+ string t="import \""+file+'\"';
+ if( !import_nest ) objectImports.push_back( t );
+ moduleImports.push_back(t);
+ }
+ }else if( ext=="c" || ext=="m" || ext=="cpp" || ext=="cxx" || ext=="cc" || ext=="mm" || ext=="s" || ext=="asm" ){
+
+ if( !ftime(path) ) fail( "File '%s' not found",path.c_str() );
+
+ }else{
+
+ fail( "Unrecognized import file type for import '%s'",path.c_str() );
+ }
+}
+
+void Parser::parseImport(){
+ if( curr()==T_IDENT ){
+ importModule( parseModuleName() );
+ }else if( curr()==T_STRINGCONST ){
+ string file=parseString();
+ if( stripall(file)=="*" ){
+ }else if( file[0]=='-' ){
+ if( !import_module ){
+ string t="import \""+file+'\"';
+ if( !import_nest ) objectImports.push_back( t );
+ moduleImports.push_back(t);
+ }
+ return;
+ }else{
+ importSource( file );
+ }
+ }else{
+ fail( "Expecting module name or import file" );
+ }
+}
+
+Parser::Parser(){
+}
+
+void Parser::parse(){
+
+ pub_=true;
+ primary=0;
+ fun_defaults=0;
+ default_call_conv=CG_CDECL;
+ import_nest=0;
+ extern_nest=0;
+ import_module=0;
+
+ Type::createTypes();
+
+ setcwd( getdir(opt_infile) );
+ toker=new Toker( opt_infile );
+ mainFun=new FunBlock();
+ block=mainFun;
+
+ ModuleType *mod_ty=new ModuleType();
+ mainFun->decls.push_back( new Decl("brl",mod_ty,lit0) );
+ mod_ty->decls.push_back( new Decl("blitz",Type::blitzModule,lit0) );
+
+ importFile( env_blitzpath+"/mod/brl.mod/blitz.mod/blitz_classes.i",Type::blitzModule );
+
+ *Type::objectClass=*Type::blitzModule->find("Object");
+ *Type::stringClass=*Type::blitzModule->find("String");
+ *Type::arrayClass=*Type::blitzModule->find("Array");
+
+ if( opt_module=="brl.blitz" ){
+ if( stripall(opt_infile)=="blitz" ){
+ rootScope.push_back( new Decl("@brl.blitz",Type::blitzModule,lit0) );
+ }
+ }else{
+ importModule( "brl.blitz" );
+ }
+
+ //if( stripall(opt_infile)!="blitz" ) importModule( "brl.blitz" );
+ //else rootScope.push_back( new Decl("@brl.blitz",Type::blitzModule,lit0) );
+
+ while( curr()!=EOF ){
+ source_info=toker->sourceInfo();
+ if( cparse('\n') ){
+ }else if( cparse( T_STRICT ) ){
+ if( strictMode ) fail( "Strict or SuperStrict already specified" );
+ strictMode=1;
+ }else if( cparse( T_SUPERSTRICT ) ){
+ if( strictMode ) fail( "Strict or SuperStrict already specified" );
+ strictMode=2;
+ }else if( cparse( T_NODEBUG ) ){
+ opt_debug=false;
+ opt_release=true;
+ block->debug_on=false;
+ }else if( cparse( T_MODULE ) ){
+ string name=parseModuleName();
+ if( name!=opt_module ) fail( "Module does not match commandline module" );
+ if( opt_apptype.size() ) fail( "Modules cannot be built as applications" );
+ }else if( cparse( T_MODULEINFO ) ){
+ if( !opt_module.size() ) fail( "ModuleInfo can only be used with modules" );
+ moduleInfos.push_back( parseString() );
+ }else if( cparse( T_FRAMEWORK ) ){
+ string framework=parseModuleName();
+ if( opt_framework.size() && opt_framework!=framework ) fail( "Framework does not match commandline framework" );
+ opt_framework=framework;
+ }else if( cparse( T_IMPORT ) ){
+ parseImport();
+ }else{
+ break;
+ }
+ }
+
+ if( opt_module.size() ){
+ }else if( opt_framework.size() ){
+ importModule( opt_framework );
+ }else{
+ vector<string> mods;
+ enumModules( "",mods );
+ for( int k=0;k<mods.size();++k ){
+ if( mods[k].find( "brl." )==0 || mods[k].find( "pub." )==0 ){
+ importModule( mods[k] );
+ }
+ }
+ }
+
+ emit( new EvalClassBlocksStm(),false );
+
+ while( curr()!=EOF ){
+ parseStm();
+ }
+
+ toker->close();
+}
--- /dev/null
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include "stm.h"
+#include "toker.h"
+
+class Parser{
+
+ Toker* toker;
+ Block* block;
+
+ bool pub_;
+ Exp* primary;
+ ExpSeq* fun_defaults;
+ int default_call_conv;
+ string loopLabel;
+ int import_nest;
+ int extern_nest;
+ ModuleType *import_module;
+
+ void fail( const char *fmt,... );
+ int curr();
+ int next();
+ string text();
+ bstring wtext();
+ string parse( int n );
+ bool cparse( int n );
+ void exp( int n );
+ void exp( string t );
+
+ bool pub();
+ int linkage();
+
+ void emitDebugInfo();
+ void emit( Stm *t,bool debugInfo );
+ void decl( Decl *d );
+
+ Type* parseLitType( Type *ty );
+ Val* parseLitVal();
+ CGExp *parseLitExp( Type *ty );
+ string parseString();
+ bstring parseBString();
+ string parseIdent();
+ string parseClassName();
+ string parseModuleName();
+
+ int parseCGType();
+ CGLit* parseCGLit();
+ CGExp* parseCGExp();
+ Decl* parseImportDecl();
+
+ void importFile( string file,ModuleType *mod );
+ void importModule( string mod );
+ void importSource( string src );
+
+ void parseImport();
+ int parseCallConv();
+ void parseExtern();
+
+ int arrayDeclDims( string t );
+
+ Type* parseBaseType();
+ FunType*parseFunType( Type *baseType );
+ Type* parseType();
+ RefType*parseRefType();
+
+ Exp* parseCastExp( Type *base_ty );
+ ArrayExp*parseArrayExp( Type *ty );
+ Exp* parsePeekExp();
+ Exp* parseIdentExp();
+
+ Exp* parseArrayDataExp();
+ Exp* parseNewExp();
+
+ Exp* parsePriExp(); //Ident, Constant, Self, Super, New(?)
+ Exp* parsePostExp( Exp *lhs=0 ); //Member, Extends, Invoke
+ Exp* parsePreExp(); //Cast, Varptr, Peek, First, Last, Before, After
+ Exp* parsePowExp(); //^
+ Exp* parseFactExp(); //*, /, Mod, Shl, Shr, Sar
+ Exp* parseTermExp(); //+, -
+ Exp* parseCmpExp(); //<, =, >, <=, >=, <>
+ Exp* parseShortCircExp(); //AndIf, OrIf
+ Exp* parseBitwiseExp(); //And, Or, Xor
+ Exp* parseExp();
+
+ string parseMetaData();
+ void addMetaData( const vector<Decl*> &decls );
+
+ Decl* parseInitDecl( Exp **init );
+
+ void parseLocalDecls();
+ void parseGlobalDecls();
+ void parseConstDecls();
+ void parseFieldDecls();
+
+ void parseTypeDecl();
+ void parseFunDecl( int attr );
+
+ void parseAccess();
+ void parseModule();
+
+ void parseLabelStm();
+ void parseGotoStm();
+ void parseFlushMemStm();
+ void parseDataStm();
+ void parseReadStm();
+ void parseRestoreStm();
+
+ void parseStm();
+ void parseEndStm();
+ void parseExpStm();
+ void parseIfStm( int term );
+ void parseLoopCtrlStm();
+ void parseForStm();
+ void parseWhileStm();
+ void parseRepeatStm();
+ void parseSelectStm();
+ void parseReturnStm();
+ void parseDeleteStm();
+ void parsePokeStm();
+ void parseAssertStm();
+ void parseTryStm();
+ void parseThrowStm();
+ void includeFile( string file );
+
+ void parseStms( Block *block,int term );
+
+public:
+ Parser();
+
+ void parse();
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "std.h"
+#include "block.h"
+#include "val.h"
+
+//******************** Scope **********************
+Scope::~Scope(){
+}
+
+Val *Scope::find( string id ){
+ return 0;
+}
+
+Val *Scope::findTypeIdent( string id ){
+
+ int i=id.find('.');
+ if( i==string::npos ){
+ globalIdent="";
+ Val *v=find( id );
+ if( !v ) v=findGlobal( id );
+ if( v && globalIdent.size() ) id=globalIdent;
+ return v;
+ }
+
+ Scope *sc=mainFun;
+ while( (i=id.find('.'))!=string::npos ){
+ Val *v=sc->find(id.substr(0,i));
+ if( !v ) return 0;
+ id=id.substr(i+1);
+ sc=v;
+ }
+ return sc->find(id);
+}
--- /dev/null
+
+#ifndef SCOPE_H
+#define SCOPE_H
+
+struct Val;
+
+struct Scope{
+ virtual ~Scope();
+
+ virtual Val* find( string id );
+
+ Val* findTypeIdent( string id );
+};
+
+#endif
--- /dev/null
+
+#include "std.h"
+#include "block.h"
+
+int strictMode;
+FunBlock *mainFun; //main function
+
+DeclSeq rootScope;
+DeclSeq objectExports; //exports from this object file
+DeclSeq moduleExports; //exports from this and imported object files
+vector<string> objectImports; //imports to this object file
+vector<string> moduleImports; //imports to this object file
+vector<string> moduleInfos;
+
+string globalIdent;
+
+set<string> importedSources; //source files already imported
+
+string fixIdent( string id ){
+ int k;
+ for( k=0;k<id.size();++k ){
+ if( !isalnum(id[k]) && id[k]!='_' ) id[k]='_';
+ }
+ return id;
+}
+
+void publish( Decl *d ){
+ objectExports.push_back(d);
+ moduleExports.push_back(d);
+}
+
+Val *findGlobal( string id ){
+ int k;
+ Val *v=0;
+ string mod;
+ for( k=rootScope.size()-1;k>=0;--k ){
+ if( Val *t=rootScope[k]->val->find(id) ){
+ if( v ){
+ fail( "Duplicate identifier '%s' in modules '%s' and '%s'",id.c_str(),mod.substr(1).c_str(),rootScope[k]->ident.substr(1).c_str() );
+ dupid( id );
+ }
+ mod=rootScope[k]->ident;
+ v=t;
+ }
+ }
+ if( v ) globalIdent=mod.substr(1)+"."+id;
+ return v;
+}
+
+CGDat *genDebugStm( string t ){
+ CGDat *d=CG::dat();
+ int i1=t.find(';');
+ if( i1!=string::npos ){
+ int i2=t.find(';',i1+1);
+ if( i2!=string::npos ){
+ string f=t.substr(0,i1);
+ string l=t.substr(i1+1,i2-i1-1);
+ string c=t.substr(i2+1);
+ fixpath( f );
+ if( !f.find(env_blitzpath+"/") ) f="$BMXPATH"+f.substr(env_blitzpath.size());
+ d->push_back( genCString(f) );
+ d->push_back( CG::lit(int(toint(l))) );
+ d->push_back( CG::lit(int(toint(c))) );
+ return d;
+ }
+ }
+ return 0;
+}
+
+CGDat *genCString( string t ){
+ static map<string,CGDat*> c_strings;
+ map<string,CGDat*>::iterator it=c_strings.find(t);
+ if( it!=c_strings.end() ) return it->second;
+ CGDat *d=CG::dat();
+ d->push_back( CG::lit(tobstring(t),CG_CSTRING) );
+ c_strings.insert( make_pair(t,d) );
+ return d;
+}
+
+CGDat *genBBString( bstring t ){
+ static map<bstring,CGDat*> bb_strings;
+ map<bstring,CGDat*>::iterator it=bb_strings.find(t);
+ if( it!=bb_strings.end() ) return it->second;
+ CGDat *d=CG::dat();
+ d->push_back( CG::sym("bbStringClass",CG_IMPORT) );
+ d->push_back( CG::lit(0x7fffffff) );
+ d->push_back( CG::lit(t,CG_BSTRING) );
+ bb_strings.insert( make_pair(t,d) );
+ return d;
+}
+
+CGDat *genBBString2( bstring t ){
+ static map<bstring,CGDat*> bb_strings2;
+ map<bstring,CGDat*>::iterator it=bb_strings2.find(t);
+ if( it!=bb_strings2.end() ) return it->second;
+ CGDat *d=CG::dat();
+ d->push_back( CG::sym("bbStringClass",CG_IMPORT) );
+ d->push_back( CG::lit(0x7ffffffe) );
+ d->push_back( CG::lit(t,CG_BSTRING) );
+ bb_strings2.insert( make_pair(t,d) );
+ return d;
+}
+
+string mungGlobal( string decl_id ){
+ return global_mung+decl_id;
+}
+
+string mungMember( string class_id,string decl_id ){
+ return "_"+global_mung+class_id+"_"+decl_id;
+}
+
+string mungObjectEntry( string path ){
+ path=tolower(realpath(path));
+ string dir=stripall(getdir(path));
+ return "__bb_"+fixIdent(dir)+"_"+fixIdent(stripall(path));
+}
+
+string mungModuleEntry( string mod ){
+ string id=moduleIdent(mod);
+//#if DEMO_VERSION
+// if( id!="appstub" ) return "__bb_"+id+"_"+id+"_";
+//#endif
+ return "__bb_"+id+"_"+id;
+}
+
+void dupid( string id,const char *fmt ){
+ fail( fmt,id.c_str() );
+}
+
+void badid( string id,const char *fmt ){
+ fail( fmt,id.c_str() );
+}
+
+void badty( string id,const char *fmt ){
+ fail( fmt,id.c_str() );
+}
+
+void badmod( string id,const char *fmt ){
+ fail( fmt,id.c_str() );
+}
+
+static void escErr(){
+ fail( "Bad escape sequence in string" );
+}
+
+bstring escapeString( bstring t ){
+ bstring r;
+ r.reserve( t.size() );
+ int i=0;
+ while( i<t.size() ){
+ int c=t[i++],esc;
+ switch( c ){
+ case '~':
+ esc='~';
+ break;
+ case '\0':
+ esc='0';
+ break;
+ case '\t':
+ esc='t';
+ break;
+ case '\r':
+ esc='r';
+ break;
+ case '\n':
+ esc='n';
+ break;
+ case '\"':
+ esc='q';
+ break;
+ default:
+ if( c>=32 && c<127 ){
+ r+=bchar_t(c);
+ }else{
+ char buf[32];
+ sprintf( buf,"~%i~",c );
+ r+=tobstring(buf);
+ }
+ continue;
+ }
+ r+=bchar_t('~');
+ r+=bchar_t(esc);
+ }
+ return r;
+}
+
+bstring unescapeString( bstring t ){
+ bstring r;
+ r.reserve( t.size() );
+ int i=0;
+ while( i<t.size() ){
+ int c=t[i++];
+ if( c!='~' ){
+ r+=bchar_t(c);
+ continue;
+ }
+ if( i==t.size() ) escErr();
+ c=t[i++];
+ switch( c ){
+ case '~':
+ r+=bchar_t('~');
+ break;
+ case '0':
+ r+=bchar_t('\0');
+ break;
+ case 't':
+ r+=bchar_t('\t');
+ break;
+ case 'r':
+ r+=bchar_t('\r');
+ break;
+ case 'n':
+ r+=bchar_t('\n');
+ break;
+ case 'q':
+ r+=bchar_t('\"');
+ break;
+ default:
+ if( c>='1' && c<='9' ){
+ int n=0;
+ while( c>='0' && c<='9' ){
+ n=n*10+(c-'0');
+ if( i==t.size() ) escErr();
+ c=t[i++];
+ }
+ if( c!='~' ) escErr();
+ r+=bchar_t(n);
+ }else{
+ escErr();
+ }
+ }
+ }
+ return r;
+}
--- /dev/null
+
+#ifndef STD_H
+#define STD_H
+
+#include "stdutil.h"
+#include "declseq.h"
+#include "../codegen/codegen.h"
+
+struct Decl;
+struct FunBlock;
+struct ClassBlock;
+struct ModuleType;
+
+extern int strictMode; //strict option : 1=strict, 2=superstrict!
+extern FunBlock* mainFun; //main function
+
+extern DeclSeq rootScope; //root scope - moduletype decls
+extern DeclSeq objectExports; //exports from this object file
+extern DeclSeq moduleExports; //exports from this and imported object files
+extern vector<string> objectImports; //'import' directives for object
+extern vector<string> moduleImports; //'import' directives for module
+extern vector<string> moduleInfos; //'ModuleInfo' directives
+
+extern set<string> importedSources; //source files already imported
+
+extern string globalIdent;
+
+string fixIdent( string id );
+
+void publish( Decl *d );
+Val* findGlobal( string id );
+
+CGDat* genCString( string t );
+CGDat* genBBString( bstring t );
+CGDat* genBBString2( bstring t );
+CGDat* genDebugStm( string t );
+
+string mungGlobal( string decl_id );
+string mungMember( string class_id,string decl_id );
+string mungObjectEntry( string path );
+string mungModuleEntry( string modname );
+
+bstring escapeString( bstring t );
+bstring unescapeString( bstring t );
+
+void dupid( string id,const char *fmt="Duplicate identifier '%s'" );
+void badid( string id,const char *fmt="Identifier '%s' not found" );
+void badty( string id,const char *fmt="Type '%s' not found" );
+void badmod( string id,const char *fmt="Module '%s' not found" );
+
+#endif
--- /dev/null
+
+#include "stdutil.h"
+
+#include <errno.h>
+#include <sys/types.h>
+
+bool opt_trace; //-z BMK0: trace dependancies
+string opt_outfile; //-o BMK0: output exe
+
+bool opt_quiet; //-q
+bool opt_verbose; //-v
+bool opt_makeall; //-a
+bool opt_debug; //-d
+bool opt_release; //-r
+bool opt_threaded;
+string opt_arch; //-g x86/ppc
+string opt_apptype; //-t apptype
+string opt_module; //-m 'modname'
+string opt_framework; //-f 'modname' or "*"
+string opt_infile;
+
+set<string> env_config;
+string env_blitzpath,env_platform,env_binpath,env_libpath,config_mung,global_mung;
+
+#if _WIN32
+
+static void init_env(){
+ char path[1024]={0};
+ GetModuleFileName( GetModuleHandle(0),path,1024 );
+ string t=path;
+ int n=t.rfind( "\\bin\\" );
+ if( n==string::npos ) n=t.rfind( "\\BIN\\" );
+ if( n==string::npos ) abort();
+ env_blitzpath=t.substr(0,n);
+
+ env_platform="win32";
+}
+
+#elif __APPLE__
+
+static void init_env(){
+
+ CFURLRef url;
+ char path[1024],*p;
+
+ url=CFBundleCopyExecutableURL( CFBundleGetMainBundle() );
+ CFURLGetFileSystemRepresentation( url,true,(UInt8*)path,1024 );
+
+ string t=path;
+ int n=t.rfind( "/bin/" );
+ if( n==string::npos ) abort();
+ env_blitzpath=t.substr(0,n);
+
+ env_platform="macos";
+}
+
+#elif __linux
+
+static void init_env(){
+
+ char linkname[256]; // /proc/<pid>/exe
+ char path[1024]={0};
+ pid_t pid;
+ int ret;
+
+ pid=getpid();
+ sprintf(linkname, "/proc/%i/exe", pid);
+ ret=readlink(linkname, path,1024);
+ if (ret<1 || ret>1022) abort();
+ path[ret]=0;
+
+ string t=path;
+ int n=t.rfind( "/bin/" );
+ if( n==string::npos ) abort();
+ env_blitzpath=t.substr(0,n);
+
+ env_platform="linux";
+}
+
+#else
+
+#error "Unsuppported build platform"
+
+#endif
+
+void stdutil_init( int argc,char *argv[] ){
+
+ init_env();
+
+ fixpath( env_blitzpath );
+
+ env_binpath=env_blitzpath+"/bin";
+ env_libpath=env_blitzpath+"/lib";
+
+#if __APPLE__
+#if __ppc__
+ if( is_pid_native(0) ) opt_arch="ppc"; else opt_arch="x86";
+#elif __i386__
+ if( is_pid_native(0) ) opt_arch="x86"; else opt_arch="ppc";
+#endif
+#else
+ opt_arch="x86";
+#endif
+ opt_debug=true;
+ opt_release=false;
+
+ for( int k=1;k<argc;++k ){
+ char *t=argv[k];
+ if( t[0]!='-' ){
+ if( opt_infile.size() ) fail( "Only one input file may be specified" );
+ opt_infile=realpath(t);
+ continue;
+ }
+ switch( t[1] ){
+ case 'q':
+ opt_quiet=true;
+ break;
+ case 'v':
+ opt_verbose=true;
+ break;
+ case 'a':
+ opt_makeall=true;
+ break;
+ case 'd':
+ opt_debug=true;
+ opt_release=false;
+ break;
+ case 'r':
+ opt_debug=false;
+ opt_release=true;
+ break;
+ case 'h':
+ opt_threaded=true;
+ break;
+ case 'z':
+ opt_trace=true;
+ break;
+ case 't':
+ if( ++k<argc ) opt_apptype=tolower(argv[k]);
+ else fail( "Command line error" );
+ break;
+ case 'g':
+ if( ++k<argc ) opt_arch=tolower(argv[k]);
+ else fail( "Command line error" );
+ break;
+ case 'm':
+ if( ++k<argc ) opt_module=tolower(argv[k]);
+ else fail( "Command line error" );
+ break;
+ case 'f':
+ if( ++k<argc ) opt_framework=tolower(argv[k]);
+ else fail( "Command line error" );
+ break;
+ case 'o':
+ if( ++k<argc ) opt_outfile=realpath( argv[k] );
+ else fail( "Command line error" );
+ break;
+ default:
+ fail( "Command line error" );
+ }
+ }
+
+ if( opt_arch=="ppc" ){
+ env_config.insert( "bigendian" );
+ }else if( opt_arch=="x86" ){
+ env_config.insert( "littleendian" );
+ }else{
+ fail( "Command line error" );
+ }
+
+ env_config.insert( opt_arch );
+ env_config.insert( env_platform );
+ env_config.insert( env_platform+opt_arch );
+ env_config.insert( opt_debug ? "debug" : "release" );
+ if( opt_threaded ) env_config.insert( "threaded" );
+
+ config_mung=opt_debug ? "debug" : "release";
+ if( opt_threaded ) config_mung+=".mt";
+ config_mung="."+config_mung+"."+env_platform+"."+opt_arch;
+
+ if( opt_module.size() ){
+ vector<string> ids;
+ splitModule( opt_module,ids );
+ int k;
+ for( k=0;k<ids.size();++k ) global_mung+=ids[k]+"_";
+ }else{
+ global_mung="bb_";
+ }
+}
+
+void fixpath( string &path ){
+ int i;
+ for( i=0;i<path.size();++i ){
+ if( path[i]=='\\' ) path[i]='/';
+ }
+}
+
+void sys( string cmd ){
+ if( opt_verbose ) cout<<cmd<<endl;
+#if _WIN32
+ // simon was here with win98 cludge
+ char path[8192];
+ int i,n;
+ n=_snprintf(path,8192,cmd.c_str());
+ for (i=0;i<n;i++)
+ {
+ if (path[i]==0) break;
+ if (path[i]=='/') path[i]='\\';
+ }
+// printf("%d%s",n,path);
+ if( system( path ) )
+ exit(-1);
+#else
+ if( system( cmd.c_str() ) )
+ exit(-1);
+#endif
+}
+
+string modulePath( string mod,bool create ){
+
+ string path=env_blitzpath+"/mod";
+ if( !mod.size() ) return path;
+ mod+=".";
+
+ while( mod.size() ){
+ int i=mod.find( '.' );
+ string t=mod.substr(0,i);
+ mod=mod.substr(i+1);
+ path+='/'+t+".mod";
+ if( create ){
+ mkdir( path.c_str(),0777 );
+ if( !ftime(path) ) fail( "mkdir failed!" );
+ }
+ }
+ return path;
+}
+
+void splitModule( string mod,vector<string> &ids ){
+ if( !mod.size() ) return;
+ int i;
+ while( (i=mod.find('.'))!=string::npos ){
+ ids.push_back(mod.substr(0,i));
+ mod=mod.substr(i+1);
+ }
+ ids.push_back(mod);
+}
+
+string moduleIdent( string mod ){
+ int i=mod.rfind('.');
+ return i==string::npos ? mod : mod.substr(i+1);
+}
+
+string moduleInterface( string mod ){
+ string path=modulePath( mod,false )+"/"+moduleIdent(mod)+config_mung+".i";
+ if( ftime( path ) ) return path;
+ fail( "Can't find interface for module '%s'",mod.c_str() );
+ return "";
+/*
+ string path=modulePath( mod,false );
+
+ string d_ext=".debug."+env_platform+"."+opt_arch+".i";
+ string r_ext=".release."+env_platform+"."+opt_arch+".i";
+
+ string f1=path+"/"+moduleIdent(mod)+r_ext;
+ string f2=path+"/"+moduleIdent(mod)+d_ext;
+ if( opt_debug ) std::swap(f1,f2);
+ if( ftime(f1) ) return f1;
+ if( ftime(f2) ) return f2;
+
+ fail( "Can't find interface for module '%s'",mod.c_str() );
+ return "";
+*/
+}
+
+void enumModules( string mod,vector<string> &mods ){
+ string path=modulePath( mod,false );
+
+ DIR *d=opendir( path.c_str() );
+ if( !d ) return;
+
+ string d_ext=".debug."+env_platform+"."+opt_arch+".i";
+ string r_ext=".release."+env_platform+"."+opt_arch+".i";
+
+ while( dirent *e=readdir( d ) ){
+ string f=e->d_name;
+ if( getext(f)!="mod" ) continue;
+ string id=stripall(f);
+ string tmod=mod.size() ? mod+"."+id : id;
+ enumModules( tmod,mods );
+ string path=modulePath( tmod,false )+"/"+id;
+ if( ftime(path+d_ext) || ftime(path+r_ext) ){
+ mods.push_back( tmod );
+ }
+ }
+ closedir(d);
+}
+
+time_t ftime( string path ){
+ struct stat st;
+ fixpath(path);
+ if( !stat( path.c_str(),&st ) ) return st.st_mtime;
+ return 0;
+}
+
+string getcwd(){
+ char buf[256];
+ if( !getcwd( buf,255 ) ) fail( "getcwd failed" );
+ string path=string(buf);
+ fixpath(path);
+ return buf;
+}
+
+void setcwd( string path ){
+ fixpath(path);
+ chdir( path.c_str() );
+}
+
+string getdir( string path ){
+ fixpath(path);
+ int n=path.rfind( '/' );
+ if( n==string::npos ) return "";
+ return path.substr(0,n);
+}
+
+string getext( string path ){
+ fixpath(path);
+ int n=path.rfind( '.' );
+ if( n==string::npos ) return "";
+ if( path.find( '/',n+1 )!=string::npos ) return "";
+ return path.substr(n+1);
+}
+
+string stripdir( string path ){
+ fixpath(path);
+ int n=path.rfind( '/' );
+ if( n==string::npos ) n=path.rfind( '\\' );
+ if( n==string::npos ) return path;
+ return path.substr(n+1);
+}
+
+string stripext( string path ){
+ fixpath(path);
+ int n=path.rfind( '.' );
+ if( n==string::npos ) return path;
+ if( path.find( '/',n+1 )!=string::npos ) return path;
+ if( path.find( '\\',n+1 )!=string::npos ) return path;
+ return path.substr(0,n);
+}
+
+string stripall( string path ){
+ return stripext(stripdir(path));
+}
+
+string realpath( string path ){
+ fixpath(path);
+ string dir=getdir(path);
+ string file=stripdir(path);
+ static char buf[MAX_PATH+8];
+ if( dir.size() ){
+// printf( "Calling realpath( %s ), MAX_PATH=%i PATH_MAX=%i\n",dir.c_str(),MAX_PATH,PATH_MAX );fflush( stdout );
+ if( !_realpath( dir.c_str(),buf ) ){
+ fail( "realpath failed for %s",path.c_str() );
+ }
+ dir=buf;
+ }else{
+ dir=getcwd();
+ }
+ fixpath( dir );
+ return dir+"/"+file;
+}
+
+string tolower( string t ){
+ for( int k=0;k<t.size();++k ){
+ t[k]=tolower(t[k]);
+ }
+ return t;
+}
+
+int64 toint( string t ){
+ if( !t.size() ) return 0;
+ int i,sgn=1;
+ for( i=0;i<t.size() && (t[i]=='+' || t[i]=='-');++i ) if( t[i]=='-' ) sgn=-sgn;
+ int64 n=0;
+ if( t[i]=='%' ){
+ for( ++i;i<t.size();++i ){
+ int c=t[i];
+ if( c!='0' && c!='1' ) break;
+ n=n*2+(c-'0');
+ }
+ }else if( t[i]=='$' ){
+ for( ++i;i<t.size();++i ){
+ int c=toupper(t[i]);
+ if( !isxdigit(c) ) break;
+ if( c>='A' ) c-=('A'-'0'-10);
+ n=n*16+(c-'0');
+ }
+ }else{
+ for( ;i<t.size();++i ){
+ int c=t[i];
+ if( !isdigit(c) ) break;
+ n=n*10+(c-'0');
+ }
+ }
+ return sgn>0 ? n : -n;
+}
+
+double tofloat( string t ){
+ double zero=0.0;
+ string q=tolower(t);
+ if( q=="nan#" ){
+ return 0.0/zero;
+ }else if( q=="inf#" || q=="+inf#" ){
+ return 1.0/zero;
+ }else if( q=="-inf#" ){
+ return -1.0/zero;
+ }
+ return atof(t.c_str());
+}
+
+string fromint( int64 n ){
+// Can't use %lld 'coz it doesn't work on mingw!
+// char buf[64];
+// sprintf( buf,"%lld",n );
+// return buf;
+ char buf[64],*p=buf+64;
+ int neg=n<0;
+ if( neg ){
+ n=-n;
+ if( n<0 ) return "-9223372036854775808";
+ }
+ *--p=0;
+ do{
+ *--p=n%10+'0';
+ }while(n/=10);
+ if( neg ) *--p='-';
+ return p;
+}
+
+string fromfloat( float n ){
+ char buf[64];
+ if( isnan(n) ){
+ sprintf( buf,"nan" );
+ }else if( isinf(n) ){
+ if( n>0 ) sprintf( buf,"inf" );
+ else sprintf( buf,"-inf" );
+ }else{
+ sprintf( buf,"%#.9g",n );
+ }
+ return buf;
+}
+
+string fromdouble( double n ){
+ char buf[64];
+ if( isnan(n) ){
+ sprintf( buf,"nan" );
+ }else if( isinf(n) ){
+ if( n>0 ) sprintf( buf,"inf" );
+ else sprintf( buf,"-inf" );
+ }else{
+ sprintf( buf,"%#.17lg",n );
+ }
+ return buf;
+}
+
+string tostring( bstring w ){
+ string t;
+ t.resize(w.size());
+ for( int k=0;k<t.size();++k ) t[k]=w[k];
+ return t;
+}
+
+bstring tobstring( string t ){
+ bstring w;
+ w.resize(t.size());
+ for( int k=0;k<w.size();++k ) w[k]=t[k] & 0xff;
+ return w;
+}
+
+bstring tobstring( const char *p ){
+ bstring w;
+ w.resize(strlen(p));
+ for( int k=0;k<w.size();++k ) w[k]=p[k] & 0xff;
+ return w;
+}
+
+string source_info;
+
+void fail( const char *fmt,... ){
+
+ char buf[256];
+
+ va_list args;
+ va_start( args,fmt );
+ vsprintf( buf,fmt,args );
+
+ cerr<<"Compile Error: "<<buf<<endl;
+ if( source_info.size() ) cerr<<"["<<source_info<<"]"<<endl;
+
+ exit(-1);
+}
+
+#if __APPLE__
+
+#include <sys/sysctl.h>
+
+static int sysctlbyname_with_pid (const char *name, pid_t pid,
+ void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen)
+{
+ if (pid == 0) {
+ if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) {
+ return -1;
+ }
+ }else{
+ int mib[CTL_MAXNAME];
+ size_t len = CTL_MAXNAME;
+ if (sysctlnametomib(name, mib, &len) == -1) {
+ return -1;
+ }
+ mib[len] = pid;
+ len++;
+ if (sysctl(mib, len, oldp, oldlenp, newp, newlen) == -1) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int is_pid_native (pid_t pid)
+{
+ int ret = 0;
+ size_t sz = sizeof(ret);
+
+ if (sysctlbyname_with_pid("sysctl.proc_native", pid, &ret, &sz, NULL, 0) == -1) {
+ if (errno == ENOENT) {
+ // sysctl doesn't exist, which means that this version of Mac OS
+ // pre-dates Rosetta, so the application must be native.
+ return 1;
+ }
+ return -1;
+ }
+ return ret;
+}
+#endif
--- /dev/null
+
+#ifndef STDUTIL_H
+#define STDUTIL_H
+
+#include <set>
+#include <map>
+#include <vector>
+#include <string>
+#include <fstream>
+#include <iostream>
+
+#include <math.h>
+#include <time.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#if _WIN32
+
+#include <windows.h>
+#include <direct.h>
+#define mkdir(X,Y) mkdir(X)
+#define _realpath(X,Y) _fullpath(Y,X,MAX_PATH)
+
+#elif __APPLE__
+
+#include <unistd.h>
+#define _realpath realpath
+#include <signal.h>
+#include <ApplicationServices/ApplicationServices.h>
+int is_pid_native (pid_t pid);
+
+//only need these with gcc-3.3 : error with gcc4
+#ifndef isnan
+extern "C"{
+int isnan( double n );
+int isinf( double n );
+}
+#endif
+
+#elif __linux
+
+#include <unistd.h>
+#define _realpath realpath
+
+#endif
+
+#include <dirent.h>
+
+#ifndef MAX_PATH
+#if PATH_MAX
+#define MAX_PATH PATH_MAX
+#else
+#define MAX_PATH 4096
+#endif
+#endif
+
+#ifdef NDEBUG
+#undef NDEBUG
+#include <assert.h>
+#define NDEBUG
+#else
+#include <assert.h>
+#endif
+
+typedef long long int64;
+
+//wchar_t and wstring a total nightmare to get going - roll our own for now!
+
+typedef unsigned short bchar_t;
+
+namespace std{
+ template<> struct char_traits<bchar_t>{
+ typedef bchar_t char_type;
+ typedef int int_type;
+ static void assign( char_type &c,char_type a ){
+ c=a;
+ }
+ static size_t length( const char_type *s ){
+ int n=0;
+ while( *s++ ) ++n;
+ return n;
+ }
+ static char_type *assign( char_type *s,size_t n,char_type a ){
+ for( size_t k=0;k<n;++k ) s[k]=a;
+ return s;
+ }
+ static char_type *copy( char_type *s1,const char_type *s2,size_t n ){
+ return static_cast<char_type*>( memcpy(s1,s2,n*sizeof(char_type)) );
+ }
+ static char_type *move( char_type *s1,const char_type *s2,size_t n ){
+ return static_cast<char_type*>( memmove(s1,s2,n*sizeof(char_type)) );
+ }
+ static const char_type *find( const char_type *s,size_t n,char_type c ){
+ for( size_t k=0;k<n;++k ) if( s[k]==c ) return s+k;
+ return 0;
+ }
+ static int compare( const char_type *s1,const char_type *s2,size_t n ){
+ for( size_t k=0;k<n;++k ) if( int t=s1[k]-s2[k] ) return t;
+ return 0;
+ }
+};
+}
+
+using namespace std;
+
+typedef basic_string<bchar_t> bstring;
+
+extern bool opt_trace; //-z BMK0: trace dependancies
+extern string opt_outfile; //-o BMK0: output exe
+
+extern bool opt_quiet; //-q
+extern bool opt_verbose; //-v
+extern bool opt_makeall; //-a
+extern bool opt_debug; //-d
+extern bool opt_release; //-r
+extern bool opt_threaded; //-h
+extern string opt_arch; //-g x86/ppc
+extern string opt_apptype; //-t apptype
+extern string opt_module; //-m 'modname'
+extern string opt_framework;//-f 'modname' or "*"
+extern string opt_infile;
+
+extern set<string> env_config;
+extern string env_blitzpath,env_platform,env_binpath,env_libpath,config_mung,global_mung;
+
+void stdutil_init( int argc,char *argv[] );
+
+//convert a dotted mod name to a path
+string modulePath( string mod,bool create );
+
+//split module components
+void splitModule( string mod,vector<string> &idents );
+
+//extract last component of a dotted mod name
+string moduleIdent( string mod );
+
+//return interface (.i) file for a module
+string moduleInterface( string mod );
+
+//enumerate modules starting with 'mod'
+void enumModules( string mod,vector<string> &mods );
+
+void sys( string cmd );
+string getcwd();
+void setcwd( string dir );
+time_t ftime( string path );
+string getdir( string path );
+string getext( string path );
+void fixpath( string &path );
+string stripdir( string path );
+string stripext( string path );
+string stripall( string path );
+string realpath( string path );
+
+int64 toint( string t );
+double tofloat( string t );
+string fromint( int64 n );
+string fromfloat( float n );
+string fromdouble( double n );
+string tolower( string str );
+string tostring( bstring w );
+bstring tobstring( string t );
+bstring tobstring( const char *p );
+
+extern string source_info;
+
+void fail( const char *fmt,... );
+
+#endif
--- /dev/null
+
+#include "std.h"
+#include "stm.h"
+#include "toker.h"
+
+using namespace CG;
+
+//******************** Stm ************************
+Stm::~Stm(){
+}
+
+//***************** SourceInfo ********************
+void DebugInfoStm::eval( Block *b ){
+ CGDat *d=genDebugStm( source_info );
+ if( d ) b->emit( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugEnterStm",CG_IMPORT),0),d)) );
+}
+
+//******************** Rem ************************
+void RemStm::eval( Block *b ){
+ if( comment.size() ) b->emit( rem(comment) );
+}
+
+//******************* StmStm **********************
+void StmStm::eval( Block *b ){
+ b->emit( stm );
+}
+
+//***************** ClassInits ********************
+void EvalClassBlocksStm::eval( Block *b ){
+ b->evalClassBlocks();
+}
+
+//******************* Label ***********************
+void LabelStm::eval( Block *b ){
+ b->emit( CG::lab(goto_sym) );
+ b->fun_block->dataStms()->push_back( lit(tobstring(restore_sym->value),CG_LABEL) );
+}
+
+//******************** Goto ***********************
+void GotoStm::eval( Block *b ){
+ if( strictMode ) fail( "Goto cannot be used in strict mode" );
+ FunBlock *f=b->fun_block;
+ map<string,LabelStm*>::iterator it=f->labels.find( tolower(ident) );
+ if( it==f->labels.end() ) fail( "Label '%s' not found",ident.c_str() );
+ b->emit( CG::bra( it->second->goto_sym ) );
+}
+
+//******************** Eval ***********************
+void EvalStm::eval( Block *b ){
+ Val *v=exp->eval(b);
+ b->emit(eva(v->cg_exp));
+}
+
+//******************** Ctor ***********************
+void CtorStm::eval( Block *b ){
+ CGExp *self=b->fun_block->fun_scope->cg_exp;
+ CGDat *vtbl=block->class_decl->val->cg_exp->dat();
+
+ ClassType *class_ty=block->type;
+ Val *super_val=class_ty->superVal();
+ ClassType *super_ty=class_ty->superClass();
+
+ //invoke super ctor
+ if( super_ty ){
+ if( Val *super_ctor=super_ty->methods.find( "New" ) ){
+ b->emit( eva( jsr( CG_PTR,CG_CDECL,vfn(super_ctor->cg_exp,self) ) ) );
+ }
+ }
+
+ //install vtbl
+ b->emit( mov( mem(CG_PTR,self,0),vtbl ) );
+
+ //initialize fields
+ block->field_ctors->eval();
+
+ ctor_new->eval();
+}
+
+//******************** Dtor ***********************
+void DtorStm::eval( Block *b ){
+
+ CGExp *self=b->fun_block->fun_scope->cg_exp;
+ CGDat *vtbl=block->class_decl->val->cg_exp->dat();
+
+ ClassType *class_ty=block->type;
+
+ dtor_delete->eval();
+
+ //return sym hack - dtor return jumps here...
+ b->emit(lab(b->fun_block->ret_sym));
+ b->fun_block->ret_sym=sym();
+
+ //destroy fields
+ for( int k=class_ty->fields.size()-1;k>=0;--k ){
+ Val *v=class_ty->decls.find( class_ty->fields[k]->ident );
+ v=v->renameTmps("@self",self);
+ if( v->refCounted() ){
+ b->emit( v->release() );
+ }
+ }
+
+ Val *super_val=class_ty->superVal();
+ ClassType *super_ty=class_ty->superClass();
+
+ //invoke super dtor
+ while( super_ty ){
+ if( Val *super_dtor=super_ty->methods.find( "Delete" ) ){
+
+ //Don't bother calling root object dtor
+ if( !super_ty->superClass() ) return;
+
+ //install super vtbl
+ b->emit( mov( mem(CG_PTR,self,0),super_val->cg_exp ) );
+
+ //invoke super dtor
+ b->emit( eva( jsr( CG_PTR,CG_CDECL,vfn(super_dtor->cg_exp,self) ) ) );
+
+ return;
+ }
+ super_val=super_ty->superVal();
+ super_ty=super_ty->superClass();
+ }
+
+ /*
+ //invoke super dtor
+ if( super_ty ){
+ //install super vtbl
+ b->emit( mov( mem(CG_PTR,self,0),super_val->cg_exp ) );
+ if( Val *super_dtor=super_ty->methods.find( "Delete" ) ){
+ b->emit( eva( jsr( CG_PTR,CG_CDECL,vfn(super_dtor->cg_exp,self) ) ) );
+ }
+ }else{
+ b->emit( mov( mem(CG_PTR,self,0),lit0 ) );
+ }
+ */
+}
+
+//***************** Local Decl ********************
+void LocalDeclStm::eval( Block *b ){
+
+ Val *i=init->evalInit( b,type );
+
+ Val *v=new Val(type,tmp(type->cgType()));
+ Decl *d=new Decl( ident,v );
+
+ FunBlock *f=b->fun_block;
+
+ if( strictMode ){
+ b->declLocal( d );
+ b->initRef( v,i );
+ }else{
+ f->declLocal( d );
+ b->assignRef( v,i );
+ }
+
+ if( !strictMode || opt_debug ){
+ f->cg_enter->push_back( mov(v->cg_exp,Val::null(type)->cg_exp) );
+ }
+}
+
+//***************** Field Decl ********************
+void FieldDeclStm::eval( Block *b ){
+
+ Val *i=init->evalInit( b,type );
+
+ Val *v=b->fun_block->fun_scope->find( ident );
+ v=b->linearizeRef(v);
+
+ b->initRef( v,i );
+}
+
+//***************** Global Decl *******************
+void GlobalDeclStm::eval( Block *b ){
+
+ Val *i=init->evalInit( b,type );
+
+ ClassBlock *cb=dynamic_cast<ClassBlock*>(b);
+
+ CGDat *e;
+ if( cb ){
+ e=dat(mungMember(cb->class_decl->ident,ident));
+ }else if( pub ){
+ e=dat(mungGlobal(ident));
+ }else{
+ e=dat();
+ }
+
+ Val *v=new Val(type,mem(type->cgType(),e,0));
+ Decl *d=new Decl( ident,v );
+
+ if( i->constant() ){
+ CGExp *t=i->cg_exp;
+ if( i->type->cgType()==CG_INT8 || i->type->cgType()==CG_INT16 ){
+ t=lit(t->lit()->int_value);
+ t->type=i->type->cgType();
+ }
+ e->push_back( t );
+ b->emit(eva(e));
+ }else{
+ e->push_back( (new Val(Type::null,0))->cast(type)->cg_exp );
+ b->initGlobalRef( v,i );
+ }
+ b->decl(d);
+ if( pub ) publish( d );
+}
+
+//***************** Extern Decl ******************
+void ExternDeclStm::eval( Block *b ){
+
+ if( !cg ) cg=sym(ident,CG_IMPORT);
+
+ switch( toke ){
+ case T_GLOBAL:cg=mem(type->cgType(),cg,0);break;
+ default:assert(0);
+ }
+ Decl *d=new Decl(ident,type,cg);
+ b->decl(d);
+ if( pub ) publish( d );
+}
+
+//****************** Import ***********************
+void ImportStm::eval( Block *b ){
+ b->emit( eva(jsr(CG_INT32,CG_CDECL,entry)) );
+}
+
+//****************** Incbin ***********************
+IncbinStm::IncbinStm( string n ):name(n),path(realpath(n)){
+}
+
+void IncbinStm::eval( Block *b ){
+
+ if( b!=mainFun ) fail( "Incbin can only be used in main program block" );
+
+ Val *v=new Val( tobstring(name) );
+
+ CGDat *d=dat();
+ CGSym *q=sym();
+
+ d->push_back(lit(tobstring(path),CG_BINFILE));
+ d->push_back(lit(tobstring(q->value),CG_LABEL));
+
+ b->cg_enter->push_back( eva(jsr(CG_INT32,"bbIncbinAdd",v->cg_exp,d,bop(CG_SUB,q,d))) );
+}
+
+//****************** Assign ***********************
+void AssignStm::eval( Block *b ){
+
+ Val *v=lhs->evalRef(b);
+
+ b->assignRef( v,rhs->evalInit(b,v->type) );
+}
+
+//****************** OpAssign *********************
+void OpAssignStm::eval( Block *b ){
+
+ Val *v=lhs->evalRef(b);
+
+ switch( op ){
+ case T_ADDASSIGN:rhs=new ArithExp('+',v,rhs);break;
+ case T_SUBASSIGN:rhs=new ArithExp('-',v,rhs);break;
+ case T_MULASSIGN:rhs=new ArithExp('*',v,rhs);break;
+ case T_DIVASSIGN:rhs=new ArithExp('/',v,rhs);break;
+ case T_MODASSIGN:rhs=new ArithExp(T_MOD,v,rhs);break;
+ case T_ORASSIGN:rhs=new BitwiseExp('|',v,rhs);break;
+ case T_ANDASSIGN:rhs=new BitwiseExp('&',v,rhs);break;
+ case T_XORASSIGN:rhs=new BitwiseExp('~',v,rhs);break;
+ case T_SHLASSIGN:rhs=new BitwiseExp(T_SHL,v,rhs);break;
+ case T_SHRASSIGN:rhs=new BitwiseExp(T_SHR,v,rhs);break;
+ case T_SARASSIGN:rhs=new BitwiseExp(T_SAR,v,rhs);break;
+ default:assert(0);
+ }
+
+ b->assignRef( v,rhs->eval(b,v->type) );
+}
+
+//***************** If Then Else ******************
+void IfStm::eval( Block *b ){
+
+ Val *v=exp->eval(b)->cond();
+
+ CGSym *t_sym=sym();
+
+ b->emit( bcc(CG_EQ,v->cg_exp,lit0,t_sym) );
+
+ then_block->eval();
+
+ if( else_block ){
+
+ CGSym *t_sym2=sym();
+ b->emit( bra(t_sym2) );
+ b->emit( lab(t_sym) );
+ t_sym=t_sym2;
+
+ else_block->eval();
+ }
+
+ b->emit(lab(t_sym));
+}
+
+//***************** Loop control ******************
+void LoopCtrlStm::eval( Block *b ){
+
+ LoopBlock *loop=0;
+ FunBlock *f=b->fun_block;
+
+ Block *p=b;
+ while( p!=f ){
+ b->emit( p->cg_leave );
+ if( loop=dynamic_cast<LoopBlock*>(p) ){
+ if( !label.size() || label==loop->label ) break;
+ }
+ p=p->outer;
+ }
+ if( p==f ){
+ if( !loop ){
+ fail( "Continue/Exit must appear inside a loop" );
+ }else{
+ fail( "Continue/Exit label '%s' not found",label.c_str() );
+ }
+ }
+
+ if( toke==T_CONTINUE ){
+ b->emit( bra(loop->cont_sym) );
+ }else{
+ b->emit( bra(loop->exit_sym) );
+ }
+}
+
+//****************** For/Next *********************
+void ForStm::eval( Block *b ){
+
+ Val *v=var->evalRef(b);
+ Type *ty=v->type;
+ if( !ty->numericType() ) fail( "Loop index variable must be of numeric type" );
+
+ Val *init_val=init->eval(b)->cast(ty);
+ Val *to_val=to->eval(b)->cast(ty);
+ Val *step_val;
+ if( step ){
+ step_val=step->eval(b)->cast(ty);
+ if( !step_val->constant() ) fail( "Step expression must be constant" );
+ }else{
+ step_val=(new Val(1))->cast(ty);
+ }
+
+ int bcc_cc=CG_LE;
+ if( ty->intType() && step_val->intValue()<0 ) bcc_cc=CG_GE;
+ if( ty->floatType() && step_val->floatValue()<0 ) bcc_cc=CG_GE;
+ if( until ) bcc_cc=(bcc_cc==CG_LE) ? CG_LT : CG_GT;
+
+ CGSym *t_sym=sym();
+
+ b->assignRef( v,init_val );
+
+ CGExp *var_exp=v->cg_exp;
+
+ if( !to_val->constant() ){
+ CGTmp *t=tmp(ty->cgType());
+ b->emit(mov(t,to_val->cg_exp));
+ to_val=new Val(ty,t);
+ }
+
+ b->emit(bra(t_sym));
+
+ b->emit(lab(block->loop_sym));
+
+ block->eval();
+
+ b->emit(lab(block->cont_sym));
+
+ b->emit(mov(var_exp,bop(CG_ADD,var_exp,step_val->cg_exp)));
+ b->emit(lab(t_sym));
+ b->emit(bcc(bcc_cc,var_exp,to_val->cg_exp,block->loop_sym));
+
+ b->emit(lab(block->exit_sym));
+}
+
+//****************** For Each *********************
+void ForEachStm::checkInt32Method( Val *v ){
+ if( v ){
+ if( FunType *ty=v->type->funType() ){
+ if( ty->method() ){
+ if( !ty->args.size() ){
+ if( ty->return_type->intType() && ty->size()==4 ) return;
+ }
+ }
+ }
+ }
+ fail( "Illegal EachIn expression" );
+}
+
+ObjectType *ForEachStm::checkObjMethod( Val *v ){
+ if( v ){
+ if( FunType *ty=v->type->funType() ){
+ if( ty->method() ){
+ if( !ty->args.size() ){
+ if( ObjectType *t=ty->return_type->objectType() ) return t;
+ }
+ }
+ }
+ }
+ fail( "Illegal EachIn expression" );
+ return 0;
+}
+
+void ForEachStm::eval( Block *b ){
+
+ Val *v=var->evalRef(b);
+ Val *t=coll->eval(b);
+
+ if( !t->type->arrayType() && !t->type->objectType() ){
+ fail( "EachIn must be used with a string, array, or appropriate object" );
+ }
+
+ Val *c=new Val( t->type,tmp(CG_PTR) );
+
+ b->emit( mov(c->cg_exp,t->cg_exp) );
+
+ if( c->type->arrayType() ){
+ evalArray( b,v,c );
+ }else{
+ evalCollection( b,v,c );
+ }
+}
+
+void ForEachStm::evalArray( Block *b,Val *var,Val *coll ){
+
+ Type *var_ty=var->type;
+ ArrayType *arr_ty=coll->type->arrayType();
+ Type *elem_ty=arr_ty->element_type;
+
+ Val *arr=new Val( arr_ty,tmp(CG_PTR) );
+
+ CGTmp *beg=tmp(CG_PTR);
+ beg->owner=coll->cg_exp->tmp();
+
+ CGTmp *end=tmp(CG_PTR);
+ end->owner=coll->cg_exp->tmp();
+
+ Val *next=new Val(elem_ty,mem(elem_ty->cgType(),beg,0));
+
+ b->emit( mov(beg,bop(CG_ADD,coll->cg_exp,lit(20+arr_ty->dims*4))) );
+ b->emit( mov(end,bop(CG_ADD,beg,mem(CG_INT32,coll->cg_exp,16))) );
+ b->emit( bra(block->cont_sym) );
+
+ //loop
+ b->emit( lab(block->loop_sym) );
+ b->assignRef( var,next->forEachCast(var_ty) );
+ b->emit( mov(beg,bop(CG_ADD,beg,lit(elem_ty->size()))) );
+ if( var_ty->objectType() ) b->emit( bcc(CG_EQ,var->cg_exp,sym("bbNullObject",CG_IMPORT),block->cont_sym) );
+
+ //statements!
+ block->eval();
+
+ //continue
+ b->emit( lab(block->cont_sym) );
+ b->emit( bcc(CG_NE,beg,end,block->loop_sym) );
+
+ //exit
+ b->emit( lab(block->exit_sym) );
+}
+
+void ForEachStm::evalCollection( Block *b,Val *var,Val *coll ){
+
+ ObjectType *var_ty=var->type->objectType();
+ if( !var_ty ) fail( "EachIn index variable must be an object" );
+
+ ObjectType *coll_ty=coll->type->objectType();
+
+ Val *enumer=coll->find( "ObjectEnumerator" );
+ ObjectType *enumer_ty=checkObjMethod( enumer );
+
+ Val *enumer_tmp=new Val( enumer_ty,tmp(CG_PTR) );
+ enumer_tmp->cg_exp->tmp()->owner=coll->cg_exp->tmp();
+
+ Val *enumer_jsr=new Val( enumer_ty,jsr(CG_PTR,CG_CDECL,enumer->cg_exp) );
+
+ Val *hasnext=enumer_tmp->find( "HasNext" );
+ checkInt32Method( hasnext );
+
+ Val *nextobj=enumer_tmp->find( "NextObject" );
+ ObjectType *nextobj_ty=checkObjMethod( nextobj );
+
+ Val *hasnext_jsr=new Val( Type::int32,jsr(CG_INT32,CG_CDECL,hasnext->cg_exp) );
+ Val *nextobj_jsr=new Val( nextobj_ty,jsr(CG_PTR,CG_CDECL,nextobj->cg_exp) );
+
+ //invoke 'ObjectEnumerator'
+ b->emit( mov(enumer_tmp->cg_exp,enumer_jsr->cg_exp) );
+ b->emit( bra(block->cont_sym) );
+
+ //loop
+ b->emit( lab(block->loop_sym) );
+ b->assignRef( var,nextobj_jsr->forEachCast(var_ty) );
+ b->emit( bcc(CG_EQ,var->cg_exp,sym("bbNullObject",CG_IMPORT),block->cont_sym) );
+
+ //statements!
+ block->eval();
+
+ //continue
+ b->emit( lab(block->cont_sym) );
+ //invoke 'HasNext'
+ b->emit( bcc(CG_NE,hasnext_jsr->cg_exp,lit0,block->loop_sym) );
+
+ //exit
+ b->emit( lab(block->exit_sym) );
+}
+
+//******************* While ***********************
+void WhileStm::eval( Block *b ){
+
+ Val *v=exp->eval(b)->cond();
+
+ b->emit(bra(block->cont_sym));
+ b->emit(lab(block->loop_sym));
+
+ block->eval();
+
+ b->emit(lab(block->cont_sym));
+ b->emit(bcc(CG_NE,v->cg_exp,lit0,block->loop_sym));
+ b->emit(lab(block->exit_sym));
+}
+
+//****************** Repeat ***********************
+void RepeatStm::eval( Block *b ){
+
+ b->emit(lab(block->loop_sym));
+ if( !exp ) b->emit(lab(block->cont_sym));
+
+ block->eval();
+
+ ::source_info=source_info;
+
+ if( exp ){
+ Val *v=exp->eval(b)->cond();
+ b->emit(lab(block->cont_sym));
+ b->emit(bcc(CG_EQ,v->cg_exp,lit0,block->loop_sym));
+ }else{
+ b->emit(bra(block->loop_sym));
+ }
+
+ b->emit(lab(block->exit_sym));
+}
+
+//****************** Return ***********************
+void ReturnStm::eval( Block *b ){
+
+ FunBlock *f=b->fun_block;
+ Type *ty=f->type->return_type;
+
+ if( exp ){
+ if( strictMode>1 && (f->type->attrs & FunType::VOIDFUN) ) fail( "Function can not return a value" );
+ }else{
+ if( strictMode>1 && !(f->type->attrs & FunType::VOIDFUN) ) fail( "Function must return a value" );
+ exp=new NullExp();
+ }
+
+ Val *v=exp->eval(b,ty);
+ b->emit( mov(f->ret_tmp,v->cg_exp) );
+
+ Block *t=b;
+ while( t!=f ){
+ b->emit(t->cg_leave);
+ t=t->outer;
+ }
+
+ b->emit( bra(f->ret_sym) );
+}
+
+//****************** Release **********************
+void ReleaseStm::eval( Block *b ){
+ Val *v=exp->evalRef(b);
+ Type *ty=v->type;
+
+ if( ty->cgType()==CG_INT32 ){
+ b->emit( eva(jsr(CG_INT32,"bbHandleRelease",v->cg_exp)) );
+ b->emit( mov(v->cg_exp,cvt(v->type->cgType(),lit0)) );
+ }else{
+ fail( "Subexpression for release must be an integer variable" );
+ }
+}
+
+//****************** delete ***********************
+void DeleteStm::eval( Block *b ){
+
+ Val *v=exp->eval(b);
+
+ ObjectType *ty=v->type->objectType();
+
+ if( !ty ) fail( "'Delete' expression does not evaluate to an object" );
+
+ b->emit( eva(jsr(CG_INT32,"bbObjectDelete",v->cg_exp)) );
+}
+
+//****************** assert ***********************
+void AssertStm::eval( Block *b ){
+
+ Val *e=exp->eval(b)->cond();
+ Val *m=msg->eval(b)->cast( Type::stringObject );
+
+ if( !opt_debug ) return;
+
+ CGSym *q=sym();
+ b->emit( bcc(CG_NE,e->cg_exp,lit0,q) );
+ b->emit( eva(jsr(CG_INT32,"brl_blitz_RuntimeError",m->cg_exp)) );
+ b->emit( lab(q) );
+}
+
+//******************** end ************************
+void EndStm::eval( Block *b ){
+
+ b->emit( eva(jsr(CG_INT32,"bbEnd")) );
+}
+
+//***************** select/case *******************
+void SelectStm::eval( Block *b ){
+
+ Val *tv=exp->eval(b);
+ Type *ty=tv->type;
+
+ Val *t_val=new Val(ty,tmp(ty->cgType()));
+ b->emit( mov(t_val->cg_exp,tv->cg_exp) );
+
+ CGSym *end=sym();
+
+ vector<CGSym*> case_syms;
+
+ int k;
+ for( k=0;k<cases.size();++k ){
+
+ SelCase *t=cases[k];
+ ::source_info=t->source_info;
+
+ case_syms.push_back( sym() );
+
+ for( int j=0;j<t->exps.size();++j ){
+
+ Val *r=t->exps[j]->eval( b,ty );
+
+ if( ty->stringType() ){
+ b->emit(
+ bcc(CG_EQ,
+ jsr(CG_INT32,"bbStringCompare",t_val->cg_exp,r->cg_exp),
+ lit0,case_syms.back()) );
+ }else{
+ b->emit(
+ bcc(CG_EQ,t_val->cg_exp,r->cg_exp,case_syms.back()) );
+ }
+ }
+ }
+
+ if( _default ) _default->eval();
+
+ b->emit( bra(end) );
+
+ for( k=0;k<cases.size();++k ){
+
+ b->emit( lab(case_syms[k]) );
+
+ Block *block=cases[k]->block;
+ block->eval();
+ b->emit( bra(end) );
+ }
+
+ b->emit( lab(end) );
+}
+
+//********************** Try *************************
+void TryStm::eval( Block *b ){
+
+ block->cg_leave->push_back(eva(jsr(CG_INT32,"bbExLeave")));
+
+ CGTmp *ex_tmp=tmp(CG_PTR);
+ CGSym *catch_sym=sym(),*exit_sym=sym();
+
+ if( opt_debug ) b->emit( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugPushExState",CG_IMPORT),0))) );
+
+ b->emit( mov(ex_tmp,jsr(CG_PTR,"bbExEnter")) );
+ b->emit( mov(ex_tmp,jsr(CG_PTR,"_bbExEnter",ex_tmp)) );
+ b->emit( bcc(CG_NE,ex_tmp,lit0,catch_sym) );
+
+ if( opt_debug ) block->cg_leave->push_back( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugPopExState",CG_IMPORT),0))) );
+
+ block->eval();
+
+ b->emit( bra(exit_sym) );
+
+ b->emit( lab(catch_sym) );
+
+ if( opt_debug ) b->emit( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugPopExState",CG_IMPORT),0))) );
+
+ //exception thrown!
+ vector<CGSym*> catch_syms;
+
+ int k;
+ for( k=0;k<catches.size();++k ){
+ TryCatch *t=catches[k];
+
+ catch_syms.push_back( sym() );
+
+ ObjectType *type=t->type->objectType();
+ if( !type ) fail( "'Catch' variables must be objects" );
+
+ CGTmp *catch_tmp=tmp(CG_PTR);
+ t->block->declLocal( new Decl(t->ident,type,catch_tmp) );
+
+ b->emit( mov(catch_tmp,jsr(CG_PTR,"bbObjectDowncast",ex_tmp,type->class_val->cg_exp)) );
+ b->emit( bcc(CG_NE,catch_tmp,sym("bbNullObject",CG_IMPORT),catch_syms.back()) );
+ }
+ b->emit( eva(jsr(CG_INT32,"bbExThrow",ex_tmp)) );
+ for( k=0;k<catches.size();++k ){
+ TryCatch *t=catches[k];
+
+ b->emit( lab(catch_syms[k]) );
+
+ t->block->eval();
+
+ b->emit( bra(exit_sym) );
+ }
+
+ b->emit( lab(exit_sym) );
+}
+
+//******************** Throw *************************
+void ThrowStm::eval( Block *b ){
+ Val *val=exp->eval( b );
+ if( !val->type->objectType() ) fail( "'Throw' expression must be an object" );
+ b->emit( eva(jsr(CG_INT32,"bbExThrow",val->cg_exp)) );
+}
+
+//********************* Data *************************
+void DataStm::eval( Block *b ){
+ int k;
+ if( b!=mainFun ) fail( "Data can only be declared in main program" );
+ FunBlock *f=mainFun;
+ CGDat *d=f->dataStms();
+ for( k=0;k<exps.size();++k ){
+ Val *v=exps[k]->eval( b );
+ if( v->type->nullType() ) fail( "Data items can not be 'Null'" );
+ if( !v->constant() ) fail( "Data items must be constant" );
+ if( v->type->intType() ) v=v->cast(Type::int32);
+ string t;
+ switch( v->type->encoding()[0] ){
+ case 'i':t="bbIntTypeTag";break;
+ case 'f':t="bbFloatTypeTag";break;
+ case 'd':t="bbDoubleTypeTag";break;
+ case '$':t="bbStringTypeTag";break;
+ default:fail( "Data items must be numeric or strings" );
+ }
+ d->push_back( sym(t,CG_IMPORT) );
+ d->push_back( v->cg_exp );
+ }
+}
+
+//******************** Restore ***********************
+void RestoreStm::eval( Block *b ){
+ FunBlock *f=mainFun;
+ map<string,LabelStm*>::iterator it=f->labels.find( tolower(ident) );
+ if( it==f->labels.end() ) fail( "Label '%s' not found",ident.c_str() );
+ b->emit( mov(mem(CG_PTR,f->dataPtr(),0),it->second->restore_sym) );
+}
+
+//********************* Read *************************
+void ReadStm::eval( Block *b ){
+ int k;
+ FunBlock *f=mainFun;
+ CGDat *d=f->dataPtr();
+ CGTmp *p=tmp(CG_PTR);
+ CGTmp *q=tmp(CG_PTR);
+ b->emit( mov(p,mem(CG_PTR,d,0)) );
+ for( k=0;k<exps.size();++k ){
+ Val *v=exps[k]->evalRef( b );
+ Type *ty=v->type;
+ if( !ty->refType() ) fail( "Read may only be used with variables" );
+ if( !ty->numericType() && !ty->stringType() ) fail( "Read may only be used with numeric or string variables" );
+ string f;
+ int cg_ty;
+ if( ty->intType() ){
+ f="bbConvertToInt";
+ cg_ty=CG_INT32;
+ }else if( ty->floatType() ){
+ f="bbConvertToFloat";
+ cg_ty=CG_FLOAT64;
+ }else if( ty->stringType() ){
+ f="bbConvertToString";
+ cg_ty=CG_PTR;
+ }else{
+ fail( "Read may only be used with numeric or string variables" );
+ }
+ b->emit( mov(q,mem(CG_PTR,p,0)) );
+ if( opt_debug ){
+ CGSym *skip=sym();
+ b->emit( bcc(CG_NE,q,lit0,skip) );
+ b->emit( eva(jsr(CG_INT32,"brl_blitz_OutOfDataError")) );
+ b->emit( lab(skip) );
+ }
+ b->emit( mov(q,mem(CG_PTR,q,0)) );
+ b->emit( mov(p,bop(CG_ADD,p,lit(4))) );
+ CGExp *e=cvt(ty->cgType(),jsr(cg_ty,f,p,q));
+ b->assignRef( v,new Val(ty,e) );
+ b->emit( mov(p,bop(CG_ADD,p,lit(4))) );
+ CGSym *skip=sym();
+ b->emit( bcc(CG_NE,mem(CG_INT8,q,0),lit('d'),skip) );
+ b->emit( mov(p,bop(CG_ADD,p,lit(4))) );
+ b->emit( lab(skip) );
+ }
+ b->emit( mov(mem(CG_PTR,d,0),p) );
+}
--- /dev/null
+
+#ifndef STM_H
+#define STM_H
+
+#include "exp.h"
+
+struct Decl;
+
+struct Stm{
+ string source_info;
+
+ virtual ~Stm();
+ virtual void eval( Block *b )=0;
+};
+
+struct DebugInfoStm : public Stm{
+ void eval( Block *b );
+};
+
+struct RemStm : public Stm{
+ string comment;
+
+ void eval( Block *b );
+};
+
+struct StmStm : public Stm{
+ CGStm *stm;
+
+ StmStm( CGStm *s ):stm(s){}
+
+ void eval( Block *b );
+};
+
+struct EvalClassBlocksStm : public Stm{
+
+ void eval( Block *b );
+};
+
+struct LabelStm : public Stm{
+ CGSym *goto_sym,*restore_sym;
+
+ LabelStm( CGSym *x,CGSym *y ):goto_sym(x),restore_sym(y){}
+
+ void eval( Block *b );
+};
+
+struct GotoStm : public Stm{
+ string ident;
+
+ GotoStm( string id ):ident(id){}
+
+ void eval( Block *b );
+};
+
+struct EvalStm : public Stm{
+ Exp *exp;
+
+ EvalStm( Exp *e ):exp(e){}
+
+ void eval( Block *b );
+};
+
+struct CtorStm : public Stm{
+ ClassBlock *block;
+ Block *ctor_new;
+
+ CtorStm( ClassBlock *b,Block *n ):block(b),ctor_new(n){}
+
+ void eval( Block *b );
+};
+
+struct DtorStm : public Stm{
+ ClassBlock *block;
+ Block *dtor_delete;
+
+ DtorStm( ClassBlock *b,Block *d ):block(b),dtor_delete(d){}
+
+ void eval( Block *b );
+};
+
+struct LocalDeclStm : public Stm{
+ string ident;
+ Type *type;
+ Exp *init;
+
+ LocalDeclStm( string id,Type *ty,Exp *e ):ident(id),type(ty),init(e){}
+
+ void eval( Block *b );
+};
+
+struct FieldDeclStm : public Stm{
+ string ident;
+ Type *type;
+ Exp *init;
+
+ FieldDeclStm( string id,Type *ty,Exp *e ):ident(id),type(ty),init(e){}
+
+ void eval( Block *b );
+};
+
+struct GlobalDeclStm : public Stm{
+ string ident;
+ Type *type;
+ Exp *init;
+ bool pub;
+
+ GlobalDeclStm( string id,Type *ty,Exp *e,bool p ):ident(id),type(ty),init(e),pub(p){}
+
+ void eval( Block *b );
+};
+
+struct ExternDeclStm : public Stm{
+ int toke;
+ string ident;
+ Type* type;
+ CGExp* cg;
+ bool pub;
+
+ ExternDeclStm( int t,string id,Type *ty,CGExp *e,bool p ):toke(t),ident(id),type(ty),cg(e),pub(p){}
+
+ void eval( Block *b );
+};
+
+struct ImportStm : public Stm{
+ CGExp *entry;
+
+ ImportStm( CGExp *e ):entry(e){}
+
+ void eval( Block *b );
+};
+
+struct IncbinStm : public Stm{
+ string name,path;
+
+ IncbinStm( string n );
+
+ void eval( Block *b );
+};
+
+struct AssignStm : public Stm{
+ Exp *lhs,*rhs;
+
+ AssignStm( Exp *l,Exp *r ):lhs(l),rhs(r){}
+
+ void eval( Block *b );
+};
+
+struct OpAssignStm : public Stm{
+ int op;
+ Exp *lhs,*rhs;
+
+ OpAssignStm( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r){}
+
+ void eval( Block *b );
+};
+
+struct IfStm : public Stm{
+ Exp *exp;
+ Block *then_block,*else_block;
+
+ IfStm( Exp *e,Block *t,Block *l ):exp(e),then_block(t),else_block(l){}
+
+ void eval( Block *b );
+};
+
+struct LoopCtrlStm : public Stm{
+ int toke;
+ string label;
+
+ LoopCtrlStm( int t,string l ):toke(t),label(l){}
+
+ void eval( Block *b );
+};
+
+struct ForStm : public Stm{
+ Exp *var;
+ Exp *init;
+ Exp *to;
+ Exp *step;
+ bool until;
+
+ LoopBlock *block;
+
+ ForStm( Exp *v,Exp *i,Exp *t,Exp *s,LoopBlock *b,bool u ):var(v),init(i),to(t),step(s),block(b),until(u){}
+
+ void eval( Block *b );
+};
+
+struct ForEachStm : public Stm{
+
+ Exp *var;
+ Exp *coll;
+
+ LoopBlock *block;
+
+ ForEachStm( Exp *v,Exp *c,LoopBlock *b ):var(v),coll(c),block(b){}
+
+ void eval( Block *b );
+
+ void evalArray( Block *b,Val *var,Val *arr );
+ void evalString( Block *b,Val *var,Val *str );
+ void evalCollection( Block *b,Val *var,Val *coll );
+
+ ObjectType *checkObjMethod( Val *v );
+ void checkInt32Method( Val *v );
+};
+
+struct WhileStm : public Stm{
+ Exp *exp;
+ LoopBlock *block;
+
+ WhileStm( Exp *e,LoopBlock *b ):exp(e),block(b){}
+
+ void eval( Block *b );
+};
+
+struct RepeatStm : public Stm{
+ Exp *exp;
+ LoopBlock *block;
+
+ RepeatStm( Exp *e,LoopBlock *b ):exp(e),block(b){}
+
+ void eval( Block *b );
+};
+
+struct ReturnStm : public Stm{
+ Exp *exp;
+
+ ReturnStm( Exp *e ):exp(e){}
+
+ void eval( Block *b );
+};
+
+struct ReleaseStm : public Stm{
+ Exp *exp;
+
+ ReleaseStm( Exp *e ):exp(e){}
+
+ void eval( Block *b );
+};
+
+struct DeleteStm : public Stm{
+ Exp *exp;
+
+ DeleteStm( Exp *e ):exp(e){}
+
+ void eval( Block *b );
+};
+
+struct SelCase{
+ ExpSeq exps;
+ Block *block;
+ string source_info;
+
+ SelCase( Block *b ):block(b){}
+};
+
+struct SelectStm : public Stm{
+ Exp *exp;
+ vector<SelCase*> cases;
+ Block *_default;
+
+ SelectStm( Exp *e ):exp(e),_default(0){}
+
+ void eval( Block *b );
+};
+
+struct AssertStm : public Stm{
+ Exp *exp,*msg;
+
+ AssertStm( Exp *e,Exp *m ):exp(e),msg(m){}
+
+ void eval( Block *b );
+};
+
+struct EndStm : public Stm{
+
+ void eval( Block *b );
+};
+
+struct TryCatch{
+ string ident;
+ Type *type;
+ Block *block;
+ string source_info;
+
+ TryCatch( Block *b ):block(b){}
+};
+
+struct TryStm : public Stm{
+ Block *block;
+ vector<TryCatch*> catches;
+
+ TryStm( Block *b ):block(b){}
+
+ void eval( Block *b );
+};
+
+struct ThrowStm : public Stm{
+ Exp *exp;
+
+ ThrowStm( Exp *e ):exp(e){}
+
+ void eval( Block *b );
+};
+
+struct DataStm : public Stm{
+ ExpSeq exps;
+
+ void eval( Block *b );
+};
+
+struct ReadStm : public Stm{
+ ExpSeq exps;
+
+ void eval( Block *b );
+};
+
+struct RestoreStm : public Stm{
+ string ident;
+
+ RestoreStm( string id ):ident(id){}
+
+ void eval( Block *b );
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "std.h"
+#include "toker.h"
+
+struct Stricmp{
+ bool operator()( const char *x,const char *y )const{
+ while( tolower(*x)==tolower(*y) && *x ){++x;++y;}
+ return tolower(*x)-tolower(*y)<0;
+ }
+};
+
+typedef map<const char*,int,Stricmp> TokeMap;
+
+static TokeMap _tokes;
+
+static void initTokes(){
+ if( _tokes.size() ) return;
+
+ _tokes["Strict"]=T_STRICT;
+ _tokes["SuperStrict"]=T_SUPERSTRICT;
+ _tokes["Module"]=T_MODULE;
+ _tokes["Framework"]=T_FRAMEWORK;
+ _tokes["Import"]=T_IMPORT;
+ _tokes["ModuleInfo"]=T_MODULEINFO;
+
+ _tokes["DefData"]=T_DEFDATA;
+ _tokes["ReadData"]=T_READDATA;
+ _tokes["RestoreData"]=T_RESTOREDATA;
+
+ _tokes["Rem"]=T_REM;
+ _tokes["EndRem"]=T_ENDREM;
+
+ _tokes["Try"]=T_TRY;
+ _tokes["Catch"]=T_CATCH;
+ _tokes["EndTry"]=T_ENDTRY;
+ _tokes["Throw"]=T_THROW;
+ _tokes["Goto"]=T_GOTO;
+
+ _tokes["True"]=T_TRUE;
+ _tokes["False"]=T_FALSE;
+ _tokes["Pi"]=T_PI;
+
+ _tokes["Byte"]=T_BYTE;
+ _tokes["Short"]=T_SHORT;
+ _tokes["Int"]=T_INT;
+ _tokes["Long"]=T_LONG;
+ _tokes["Float"]=T_FLOAT;
+ _tokes["Double"]=T_DOUBLE;
+ _tokes["Object"]=T_OBJECT;
+ _tokes["String"]=T_STRING;
+
+ _tokes["Var"]=T_VAR;
+ _tokes["Ptr"]=T_PTR;
+ _tokes["VarPtr"]=T_VARPTR;
+
+ _tokes["Chr"]=T_CHR;
+ _tokes["Len"]=T_LEN;
+ _tokes["Asc"]=T_ASC;
+ _tokes["SizeOf"]=T_SIZEOF;
+
+ _tokes["Sgn"]=T_SGN;
+
+ _tokes["Abs"]=T_ABS;
+ _tokes["Min"]=T_MIN;
+ _tokes["Max"]=T_MAX;
+ _tokes["Mod"]=T_MOD;
+
+ _tokes["Shl"]=T_SHL;
+ _tokes["Shr"]=T_SHR;
+ _tokes["Sar"]=T_SAR;
+
+ _tokes["Not"]=T_NOT;
+ _tokes["And"]=T_AND;
+ _tokes["Or"]=T_OR;
+
+ _tokes["Return"]=T_RETURN;
+
+ _tokes["Local"]=T_LOCAL;
+ _tokes["Global"]=T_GLOBAL;
+ _tokes["Const"]=T_CONST;
+ _tokes["Field"]=T_FIELD;
+ _tokes["Alias"]=T_ALIAS;
+ _tokes["End"]=T_END;
+
+ _tokes["Type"]=T_TYPE;
+ _tokes["EndType"]=T_ENDTYPE;
+ _tokes["Extends"]=T_EXTENDS;
+
+ _tokes["Method"]=T_METHOD;
+ _tokes["EndMethod"]=T_ENDMETHOD;
+ _tokes["Abstract"]=T_ABSTRACT;
+ _tokes["Final"]=T_FINAL;
+
+ _tokes["Function"]=T_FUNCTION;
+ _tokes["EndFunction"]=T_ENDFUNCTION;
+
+ _tokes["New"]=T_NEW;
+ _tokes["Release"]=T_RELEASE;
+ _tokes["Delete"]=T_DELETE;
+
+ _tokes["Null"]=T_NULL;
+ _tokes["Self"]=T_SELF;
+ _tokes["Super"]=T_SUPER;
+
+ _tokes["Incbin"]=T_INCBIN;
+ _tokes["IncbinPtr"]=T_INCBINPTR;
+ _tokes["IncbinLen"]=T_INCBINLEN;
+
+ _tokes["Include"]=T_INCLUDE;
+ _tokes["Extern"]=T_EXTERN;
+ _tokes["EndExtern"]=T_ENDEXTERN;
+
+ _tokes["Public"]=T_PUBLIC;
+ _tokes["Private"]=T_PRIVATE;
+
+ _tokes["If"]=T_IF;
+ _tokes["Then"]=T_THEN;
+ _tokes["Else"]=T_ELSE;
+ _tokes["ElseIf"]=T_ELSEIF;
+ _tokes["EndIf"]=T_ENDIF;
+
+ _tokes["For"]=T_FOR;
+ _tokes["To"]=T_TO;
+ _tokes["Step"]=T_STEP;
+ _tokes["Next"]=T_NEXT;
+ _tokes["EachIn"]=T_EACHIN;
+
+ _tokes["While"]=T_WHILE;
+ _tokes["EndWhile"]=T_WEND;
+ _tokes["Wend"]=T_WEND;
+
+ _tokes["Repeat"]=T_REPEAT;
+ _tokes["Until"]=T_UNTIL;
+ _tokes["Forever"]=T_FOREVER;
+
+ _tokes["Select"]=T_SELECT;
+ _tokes["Case"]=T_CASE;
+ _tokes["Default"]=T__DEFAULT;
+ _tokes["EndSelect"]=T_ENDSELECT;
+
+ _tokes["Continue"]=T_CONTINUE;
+ _tokes["Exit"]=T_EXIT;
+
+ _tokes["Assert"]=T_ASSERT;
+
+ _tokes["NoDebug"]=T_NODEBUG;
+}
+
+static Toke nextToke( const vector<char> &line,int &p ){
+
+ int b=p;
+ int c=line[p++];
+ int cur=c;
+
+ if( isalpha(c) || c=='_' ){
+ while( isalnum( c=line[p] ) || c=='_' ) ++p;
+ cur=T_IDENT;
+ string t( &line[b],p-b );
+ TokeMap::iterator it=_tokes.find(t.c_str());
+ if( it!=_tokes.end() ){
+ cur=it->second;
+ if( cur==T_END && line[p]==' ' && isalpha(line[p+1]) ){
+ int st=p+1,en=p+2;
+ while( isalpha(line[en]) ) ++en;
+ string t="end"+string( &line[st],en-st );
+ it=_tokes.find(t.c_str());
+ if( it!=_tokes.end() ){
+ cur=it->second;
+ p=en;
+ }
+ }
+ }
+ }else if( isdigit(c) || (c=='.' && isdigit(line[p])) ){
+ cur=T_INTCONST;
+ if( c=='.' ){
+ ++p;cur=T_FLOATCONST;
+ }
+ while( isdigit(line[p]) ) ++p;
+ if( cur==T_INTCONST && line[p]=='.' && isdigit(line[p+1]) ){
+ p+=2;cur=T_FLOATCONST;
+ while( isdigit(line[p]) ) ++p;
+ }
+ if( tolower(line[p])=='e' && (line[p+1]=='+'||line[p+1]=='-'||isdigit(line[p+1])) ){
+ ++p;cur=T_FLOATCONST;
+ if( !isdigit(line[p]) ) ++p;
+ while( isdigit(line[p]) ) ++p;
+ }
+ }else if( c=='$' && isxdigit(line[p]) ){
+ ++p;cur=T_INTCONST;
+ while( isxdigit(line[p]) ) ++p;
+ }else if( c=='%' && (line[p]=='0'||line[p]=='1') ){
+ ++p;cur=T_INTCONST;
+ while( line[p]=='0' || line[p]=='1' ) ++p;
+ }else if( c=='$' && tolower(line[p])=='z' ){
+ ++p;cur=T_CSTRING;
+ }else if( c=='$' && tolower(line[p])=='w' ){
+ ++p;cur=T_WSTRING;
+ }else if( c=='\"' ){ //string const
+ while( line[p]!='\"' && line[p]!='\n' ) ++p;
+ if( line[p]=='\"' ){
+ cur=T_STRINGCONST;
+ ++p;
+ }else{
+ cur=T_BADSTRINGCONST;
+ }
+ /*
+ cur=T_STRINGCONST;
+ while( line[p]!='\"' && line[p]!='\n' ) ++p;
+ if( line[p++]!='\"' ) cur=T_BADSTRINGCONST;
+ */
+
+ }else if( c=='<' ){ //comparison
+ switch( line[p++] ){
+ case '=':cur=T_LE;break;
+ case '>':cur=T_NE;break;
+ default:cur=T_LT;--p;
+ }
+ }else if( c=='=' ){ //comparison
+ switch( line[p++] ){
+ case '>':cur=T_GE;break;
+ case '<':cur=T_LE;break;
+ default:cur=T_EQ;--p;
+ }
+ }else if( c=='>' ){ //comparison
+ switch( line[p++] ){
+ case '=':cur=T_GE;break;
+ case '<':cur=T_NE;break;
+ default:cur=T_GT;--p;
+ }
+ }else if( c==':' ){
+ Toke t=nextToke( line,p );
+ switch( t.toke ){
+ case '+':cur=T_ADDASSIGN;break;
+ case '-':cur=T_SUBASSIGN;break;
+ case '*':cur=T_MULASSIGN;break;
+ case '/':cur=T_DIVASSIGN;break;
+ case '|':cur=T_ORASSIGN;break;
+ case '&':cur=T_ANDASSIGN;break;
+ case '~':cur=T_XORASSIGN;break;
+ case T_MOD:cur=T_MODASSIGN;break;
+ case T_SHL:cur=T_SHLASSIGN;break;
+ case T_SHR:cur=T_SHRASSIGN;break;
+ case T_SAR:cur=T_SARASSIGN;break;
+ default:p=b+1;
+ }
+ }else if( c=='.' && line[p]=='.' ){
+ ++p;cur=T_DOTDOT;
+ }else if( c=='[' ){ //allow spaces in [,] type tokes
+ while( line[p]==' ' || line[p]==',' ) ++p;
+ if( line[p]==']' ){
+ ++p;cur=T_ARRAYDECL;
+ }else{
+ p=b+1;
+ }
+ }
+ return Toke( cur,b,p );
+}
+
+Toker::Toker( string f ):fh(0),toke_index(0),line_num(0),file_name(f){
+ initTokes();
+
+ fh=fopen( file_name.c_str(),"rb" );
+ if( !fh ) fail( "Unable to open file '%s'",file_name.c_str() );
+
+ encoding=UNK;
+
+ next();
+}
+
+void Toker::close(){
+ if( fh ){
+ fclose( fh );
+ fh=0;
+ }
+}
+
+string Toker::sourceFile(){
+ return file_name;
+}
+
+string Toker::sourceInfo(){
+ return file_name+";"+fromint(line_num)+";"+fromint(curr_toke.begin+1);
+}
+
+int Toker::curr(){
+ return curr_toke.toke;
+}
+
+string Toker::text(){
+ return string( &line[curr_toke.begin],curr_toke.end-curr_toke.begin );
+}
+
+bstring Toker::wtext(){
+ return bstring( &wline[curr_toke.begin],curr_toke.end-curr_toke.begin );
+}
+
+int Toker::peek( int n ){
+ assert( toke_index+n<tokes.size() );
+ return tokes[toke_index+n].toke;
+}
+
+int Toker::tgetc(){
+
+ int c=fgetc(fh),d,e;
+ if( c==EOF ) return c;
+
+ switch( encoding ){
+ case UNK:
+ d=fgetc(fh);
+ if( c==0xfe && d==0xff ){
+ encoding=UTF16BE;
+ }else if( c==0xff && d==0xfe ){
+ encoding=UTF16LE;
+ }else if( c==0xef && d==0xbb ){
+ e=fgetc(fh);
+ if( e==0xbf ){
+ encoding=UTF8;
+ }else{
+ ungetc( e,fh );
+ }
+ }
+ if( encoding==UNK ){
+ encoding=LATIN1;
+ ungetc( d,fh );
+ ungetc( c,fh );
+ }
+ return tgetc();
+ case LATIN1:
+ return c;
+ case UTF8:
+ if( c<128 ){
+ return c;
+ }
+ d=fgetc(fh);
+ if( c<224 ){
+ return (c-192)*64+(d-128);
+ }
+ e=fgetc(fh);
+ if( c<240 ){
+ return (c-224)*4096+(d-128)*64+(e-128);
+ }
+ return 0;
+ case UTF16BE:
+ return ((c&0xff)<<8)|(fgetc(fh)&0xff);
+ case UTF16LE:
+ return ((fgetc(fh)&0xff)<<8)|(c&0xff);
+ }
+ cout<<"Here!"<<endl;
+ return ' ';
+}
+
+void Toker::nextLine(){
+
+ ++line_num;
+ line.clear();
+ wline.clear();
+ tokes.clear();
+
+ if( !fh ){
+ tokes.push_back( Toke(EOF,0,0) );
+ return;
+ }
+
+ for(;;){
+ int c=tgetc();
+ if( c=='\n' || c==EOF ){
+ if( c==EOF ) close();
+ line.push_back( '\n' );
+ wline.push_back( '\n' );
+ break;
+ }
+ line.push_back( (c>32 && c<127) ? c : ' ' );
+ wline.push_back(c);
+ }
+
+ int p=0;
+ for(;;){
+ int c=line[p];
+ if( c=='\'' || c=='\n' ){
+ if( tokes.size() && tokes.back().toke==T_DOTDOT ){
+ tokes.pop_back();
+ break;
+ }
+ tokes.push_back( Toke('\n',p,line.size()) );
+ break;
+ }else if( isgraph(c) ){
+ tokes.push_back( nextToke(line,p) );
+ }else{
+ ++p;
+ }
+ }
+}
+
+int Toker::next(){
+
+ if( curr()==EOF ) return EOF;
+
+ while( toke_index==tokes.size() ){
+
+ nextLine();
+ toke_index=0;
+
+ for(;;){
+ if( !tokes.size() ){
+ nextLine();
+ }else if( tokes[0].toke=='?' ){
+ ++toke_index;
+ bool cc=true,cNot=false;
+ if( toke_index<tokes.size() && tokes[toke_index].toke==T_NOT ){
+ ++toke_index;
+ cNot=true;
+ }
+ if( toke_index<tokes.size() && tokes[toke_index].toke==T_IDENT ){
+ string id=string( &line[tokes[toke_index].begin],tokes[toke_index].end-tokes[toke_index].begin );
+ ++toke_index;
+ cc=env_config.count( tolower(id) );
+ }
+ if( cNot ) cc=!cc;
+ if( cc ) break;
+ do{
+ nextLine();
+ }while( tokes[0].toke!=EOF && tokes[0].toke!='?' );
+ toke_index=0;
+ }else if( tokes[0].toke==T_REM ){
+ do{
+ nextLine();
+ }while( tokes[0].toke!=EOF && tokes[0].toke!=T_ENDREM );
+ if( tokes[0].toke==EOF ) break;
+ nextLine();
+ }else{
+ break;
+ }
+ }
+ }
+
+ curr_toke=tokes[toke_index++];
+ return curr();
+}
+
+string Toker::toString( int n ){
+ switch( n ){
+ case '\n':return "end-of-line";
+ case EOF:return "end-of-file";
+ case T_LT:return "'<'";
+ case T_GT:return "'>'";
+ case T_LE:return "'<='";
+ case T_GE:return "'>='";
+ case T_EQ:return "'='";
+ case T_NE:return "'<>'";
+ case T_DOTDOT:return "'..'";
+ case T_IDENT:return "identifier";
+ case T_INTCONST:return "integer literal";
+ case T_FLOATCONST:return "floating point literal";
+ case T_STRINGCONST:return "string literal";
+ case T_CSTRING:return "cstring tag";
+ case T_WSTRING:return "wstring tag";
+ case T_ARRAYDECL:return "array declaration";
+ case T_BADSTRINGCONST:return "malformed string literal";
+ case T_ADDASSIGN:return "add assign";
+ case T_SUBASSIGN:return "subtract assign";
+ case T_MULASSIGN:return "multiply assign";
+ case T_DIVASSIGN:return "divide assign";
+ case T_MODASSIGN:return "remainder assign";
+ case T_ORASSIGN:return "or assign";
+ case T_ANDASSIGN:return "and assign";
+ case T_XORASSIGN:return "exclusive or assign";
+ case T_SHLASSIGN:return "shift left assign";
+ case T_SHRASSIGN:return "shift right assign";
+ case T_SARASSIGN:return "Shift arithmetic right assign";
+ }
+ TokeMap::iterator it;
+ for( it=_tokes.begin();it!=_tokes.end();++it ){
+ if( n==it->second ) return it->first;
+ }
+ if( isgraph(n) ){
+ char c=n;
+ return "'"+string(&c,1)+"'";
+ }
+ char buf[8];
+ sprintf( buf,"%i",n );
+ return "<chr:"+string(buf)+">";
+}
--- /dev/null
+
+#include "std.h"
+#include "toker.h"
+
+struct Stricmp{
+ bool operator()( const char *x,const char *y )const{
+ while( tolower(*x)==tolower(*y) && *x ){++x;++y;}
+ return tolower(*x)-tolower(*y)<0;
+ }
+};
+
+typedef map<const char*,int,Stricmp> TokeMap;
+
+static TokeMap _tokes;
+
+static void initTokes(){
+ if( _tokes.size() ) return;
+
+ _tokes["Strict"]=T_STRICT;
+ _tokes["SuperStrict"]=T_SUPERSTRICT;
+ _tokes["Module"]=T_MODULE;
+ _tokes["Framework"]=T_FRAMEWORK;
+ _tokes["Import"]=T_IMPORT;
+ _tokes["ModuleInfo"]=T_MODULEINFO;
+
+ _tokes["DefData"]=T_DEFDATA;
+ _tokes["ReadData"]=T_READDATA;
+ _tokes["RestoreData"]=T_RESTOREDATA;
+
+ _tokes["Rem"]=T_REM;
+ _tokes["EndRem"]=T_ENDREM;
+
+ _tokes["Try"]=T_TRY;
+ _tokes["Catch"]=T_CATCH;
+ _tokes["EndTry"]=T_ENDTRY;
+ _tokes["Throw"]=T_THROW;
+ _tokes["Goto"]=T_GOTO;
+
+ _tokes["True"]=T_TRUE;
+ _tokes["False"]=T_FALSE;
+ _tokes["Pi"]=T_PI;
+
+ _tokes["Byte"]=T_BYTE;
+ _tokes["Short"]=T_SHORT;
+ _tokes["Int"]=T_INT;
+ _tokes["Long"]=T_LONG;
+ _tokes["Float"]=T_FLOAT;
+ _tokes["Double"]=T_DOUBLE;
+ _tokes["Object"]=T_OBJECT;
+ _tokes["String"]=T_STRING;
+
+ _tokes["Var"]=T_VAR;
+ _tokes["Ptr"]=T_PTR;
+ _tokes["VarPtr"]=T_VARPTR;
+
+ _tokes["Chr"]=T_CHR;
+ _tokes["Len"]=T_LEN;
+ _tokes["Asc"]=T_ASC;
+ _tokes["SizeOf"]=T_SIZEOF;
+
+ _tokes["Sgn"]=T_SGN;
+
+ _tokes["Abs"]=T_ABS;
+ _tokes["Min"]=T_MIN;
+ _tokes["Max"]=T_MAX;
+ _tokes["Mod"]=T_MOD;
+
+ _tokes["Shl"]=T_SHL;
+ _tokes["Shr"]=T_SHR;
+ _tokes["Sar"]=T_SAR;
+
+ _tokes["Not"]=T_NOT;
+ _tokes["And"]=T_AND;
+ _tokes["Or"]=T_OR;
+
+ _tokes["Return"]=T_RETURN;
+
+ _tokes["Local"]=T_LOCAL;
+ _tokes["Global"]=T_GLOBAL;
+ _tokes["Const"]=T_CONST;
+ _tokes["Field"]=T_FIELD;
+ _tokes["Alias"]=T_ALIAS;
+ _tokes["End"]=T_END;
+
+ _tokes["Type"]=T_TYPE;
+ _tokes["EndType"]=T_ENDTYPE;
+ _tokes["Extends"]=T_EXTENDS;
+
+ _tokes["Method"]=T_METHOD;
+ _tokes["EndMethod"]=T_ENDMETHOD;
+ _tokes["Abstract"]=T_ABSTRACT;
+ _tokes["Final"]=T_FINAL;
+
+ _tokes["Function"]=T_FUNCTION;
+ _tokes["EndFunction"]=T_ENDFUNCTION;
+
+ _tokes["New"]=T_NEW;
+ _tokes["Release"]=T_RELEASE;
+ _tokes["Delete"]=T_DELETE;
+
+ _tokes["Null"]=T_NULL;
+ _tokes["Self"]=T_SELF;
+ _tokes["Super"]=T_SUPER;
+
+ _tokes["Incbin"]=T_INCBIN;
+ _tokes["IncbinPtr"]=T_INCBINPTR;
+ _tokes["IncbinLen"]=T_INCBINLEN;
+
+ _tokes["Include"]=T_INCLUDE;
+ _tokes["Extern"]=T_EXTERN;
+ _tokes["EndExtern"]=T_ENDEXTERN;
+
+ _tokes["Public"]=T_PUBLIC;
+ _tokes["Private"]=T_PRIVATE;
+
+ _tokes["If"]=T_IF;
+ _tokes["Then"]=T_THEN;
+ _tokes["Else"]=T_ELSE;
+ _tokes["ElseIf"]=T_ELSEIF;
+ _tokes["EndIf"]=T_ENDIF;
+
+ _tokes["For"]=T_FOR;
+ _tokes["To"]=T_TO;
+ _tokes["Step"]=T_STEP;
+ _tokes["Next"]=T_NEXT;
+ _tokes["EachIn"]=T_EACHIN;
+
+ _tokes["While"]=T_WHILE;
+ _tokes["EndWhile"]=T_WEND;
+ _tokes["Wend"]=T_WEND;
+
+ _tokes["Repeat"]=T_REPEAT;
+ _tokes["Until"]=T_UNTIL;
+ _tokes["Forever"]=T_FOREVER;
+
+ _tokes["Select"]=T_SELECT;
+ _tokes["Case"]=T_CASE;
+ _tokes["Default"]=T__DEFAULT;
+ _tokes["EndSelect"]=T_ENDSELECT;
+
+ _tokes["Continue"]=T_CONTINUE;
+ _tokes["Exit"]=T_EXIT;
+
+ _tokes["Assert"]=T_ASSERT;
+
+ _tokes["NoDebug"]=T_NODEBUG;
+}
+
+static Toke nextToke( const vector<char> &line,int &p ){
+
+ int b=p;
+ int c=line[p++];
+ int cur=c;
+
+ if( isalpha(c) || c=='_' ){
+ while( isalnum( c=line[p] ) || c=='_' ) ++p;
+ cur=T_IDENT;
+ string t( &line[b],p-b );
+ TokeMap::iterator it=_tokes.find(t.c_str());
+ if( it!=_tokes.end() ){
+ cur=it->second;
+ if( cur==T_END && line[p]==' ' && isalpha(line[p+1]) ){
+ int st=p+1,en=p+2;
+ while( isalpha(line[en]) ) ++en;
+ string t="end"+string( &line[st],en-st );
+ it=_tokes.find(t.c_str());
+ if( it!=_tokes.end() ){
+ cur=it->second;
+ p=en;
+ }
+ }
+ }
+ }else if( isdigit(c) || (c=='.' && isdigit(line[p])) ){
+ cur=T_INTCONST;
+ if( c=='.' ){
+ ++p;cur=T_FLOATCONST;
+ }
+ while( isdigit(line[p]) ) ++p;
+ if( cur==T_INTCONST && line[p]=='.' && isdigit(line[p+1]) ){
+ p+=2;cur=T_FLOATCONST;
+ while( isdigit(line[p]) ) ++p;
+ }
+ if( tolower(line[p])=='e' && (line[p+1]=='+'||line[p+1]=='-'||isdigit(line[p+1])) ){
+ ++p;cur=T_FLOATCONST;
+ if( !isdigit(line[p]) ) ++p;
+ while( isdigit(line[p]) ) ++p;
+ }
+ }else if( c=='$' && isxdigit(line[p]) ){
+ ++p;cur=T_INTCONST;
+ while( isxdigit(line[p]) ) ++p;
+ }else if( c=='%' && (line[p]=='0'||line[p]=='1') ){
+ ++p;cur=T_INTCONST;
+ while( line[p]=='0' || line[p]=='1' ) ++p;
+ }else if( c=='$' && tolower(line[p])=='z' ){
+ ++p;cur=T_CSTRING;
+ }else if( c=='$' && tolower(line[p])=='w' ){
+ ++p;cur=T_WSTRING;
+ }else if( c=='\"' ){ //string const
+ cur=T_STRINGCONST;
+ while( line[p]!='\"' && line[p]!='\n' ) ++p;
+ if( line[p++]!='\"' ) cur=T_BADSTRINGCONST;
+ }else if( c=='<' ){ //comparison
+ switch( line[p++] ){
+ case '=':cur=T_LE;break;
+ case '>':cur=T_NE;break;
+ default:cur=T_LT;--p;
+ }
+ }else if( c=='=' ){ //comparison
+ switch( line[p++] ){
+ case '>':cur=T_GE;break;
+ case '<':cur=T_LE;break;
+ default:cur=T_EQ;--p;
+ }
+ }else if( c=='>' ){ //comparison
+ switch( line[p++] ){
+ case '=':cur=T_GE;break;
+ case '<':cur=T_NE;break;
+ default:cur=T_GT;--p;
+ }
+ }else if( c==':' ){
+ Toke t=nextToke( line,p );
+ switch( t.toke ){
+ case '+':cur=T_ADDASSIGN;break;
+ case '-':cur=T_SUBASSIGN;break;
+ case '*':cur=T_MULASSIGN;break;
+ case '/':cur=T_DIVASSIGN;break;
+ case '|':cur=T_ORASSIGN;break;
+ case '&':cur=T_ANDASSIGN;break;
+ case '~':cur=T_XORASSIGN;break;
+ case T_MOD:cur=T_MODASSIGN;break;
+ case T_SHL:cur=T_SHLASSIGN;break;
+ case T_SHR:cur=T_SHRASSIGN;break;
+ case T_SAR:cur=T_SARASSIGN;break;
+ default:p=b+1;
+ }
+ }else if( c=='.' && line[p]=='.' ){
+ ++p;cur=T_DOTDOT;
+ }else if( c=='[' ){ //allow spaces in [,] type tokes
+ while( line[p]==' ' || line[p]==',' ) ++p;
+ if( line[p]==']' ){
+ ++p;cur=T_ARRAYDECL;
+ }else{
+ p=b+1;
+ }
+ }
+ return Toke( cur,b,p );
+}
+
+Toker::Toker( string f ):fh(0),toke_index(0),line_num(0),file_name(f){
+ initTokes();
+
+ fh=fopen( file_name.c_str(),"rb" );
+ if( !fh ) fail( "Unable to open file '%s'",file_name.c_str() );
+
+ encoding=UNK;
+
+ next();
+}
+
+void Toker::close(){
+ if( fh ){
+ fclose( fh );
+ fh=0;
+ }
+}
+
+string Toker::sourceFile(){
+ return file_name;
+}
+
+string Toker::sourceInfo(){
+ return file_name+";"+fromint(line_num)+";"+fromint(curr_toke.begin+1);
+}
+
+int Toker::curr(){
+ return curr_toke.toke;
+}
+
+string Toker::text(){
+ return string( &line[curr_toke.begin],curr_toke.end-curr_toke.begin );
+}
+
+bstring Toker::wtext(){
+ return bstring( &wline[curr_toke.begin],curr_toke.end-curr_toke.begin );
+}
+
+int Toker::peek( int n ){
+ assert( toke_index+n<tokes.size() );
+ return tokes[toke_index+n].toke;
+}
+
+int Toker::tgetc(){
+
+ int c=fgetc(fh),d,e;
+ if( c==EOF ) return c;
+
+ switch( encoding ){
+ case UNK:
+ d=fgetc(fh);
+ if( c==0xfe && d==0xff ){
+ encoding=UTF16BE;
+ }else if( c==0xff && d==0xfe ){
+ encoding=UTF16LE;
+ }else if( c==0xef && d==0xbb ){
+ e=fgetc(fh);
+ if( e==0xbf ){
+ encoding=UTF8;
+ }else{
+ ungetc( e,fh );
+ }
+ }
+ if( encoding==UNK ){
+ encoding=LATIN1;
+ ungetc( d,fh );
+ ungetc( c,fh );
+ }
+ return tgetc();
+ case LATIN1:
+ return c;
+ case UTF8:
+ if( c<128 ){
+ return c;
+ }
+ d=fgetc(fh);
+ if( c<224 ){
+ return (c-192)*64+(d-128);
+ }
+ e=fgetc(fh);
+ if( c<240 ){
+ return (c-224)*4096+(d-128)*64+(e-128);
+ }
+ return 0;
+ case UTF16BE:
+ return ((c&0xff)<<8)|(fgetc(fh)&0xff);
+ case UTF16LE:
+ return ((fgetc(fh)&0xff)<<8)|(c&0xff);
+ }
+ cout<<"Here!"<<endl;
+ return ' ';
+}
+
+void Toker::nextLine(){
+
+ ++line_num;
+ line.clear();
+ wline.clear();
+ tokes.clear();
+
+ if( !fh ){
+ tokes.push_back( Toke(EOF,0,0) );
+ return;
+ }
+
+ for(;;){
+ int c=tgetc();
+ if( c=='\n' || c==EOF ){
+ if( c==EOF ) close();
+ line.push_back( '\n' );
+ wline.push_back( '\n' );
+ break;
+ }
+ line.push_back( (c>32 && c<127) ? c : ' ' );
+ wline.push_back(c);
+ }
+
+ int p=0;
+ for(;;){
+ int c=line[p];
+ if( c=='\'' || c=='\n' ){
+ if( tokes.size() && tokes.back().toke==T_DOTDOT ){
+ tokes.pop_back();
+ break;
+ }
+ tokes.push_back( Toke('\n',p,line.size()) );
+ break;
+ }else if( isgraph(c) ){
+ tokes.push_back( nextToke(line,p) );
+ }else{
+ ++p;
+ }
+ }
+}
+
+int Toker::next(){
+
+ if( curr()==EOF ) return EOF;
+
+ while( toke_index==tokes.size() ){
+
+ nextLine();
+ toke_index=0;
+
+ for(;;){
+ if( !tokes.size() ){
+ nextLine();
+ }else if( tokes[0].toke=='?' ){
+ ++toke_index;
+ bool cc=true,cNot=false;
+ if( toke_index<tokes.size() && tokes[toke_index].toke==T_NOT ){
+ ++toke_index;
+ cNot=true;
+ }
+ if( toke_index<tokes.size() && tokes[toke_index].toke==T_IDENT ){
+ string id=string( &line[tokes[toke_index].begin],tokes[toke_index].end-tokes[toke_index].begin );
+ ++toke_index;
+ cc=env_config.count( tolower(id) );
+ }
+ if( cNot ) cc=!cc;
+ if( cc ) break;
+ do{
+ nextLine();
+ }while( tokes[0].toke!=EOF && tokes[0].toke!='?' );
+ toke_index=0;
+ }else if( tokes[0].toke==T_REM ){
+ do{
+ nextLine();
+ }while( tokes[0].toke!=EOF && tokes[0].toke!=T_ENDREM );
+ if( tokes[0].toke==EOF ) break;
+ nextLine();
+ }else{
+ break;
+ }
+ }
+ }
+
+ curr_toke=tokes[toke_index++];
+ return curr();
+}
+
+string Toker::toString( int n ){
+ switch( n ){
+ case '\n':return "end-of-line";
+ case EOF:return "end-of-file";
+ case T_LT:return "'<'";
+ case T_GT:return "'>'";
+ case T_LE:return "'<='";
+ case T_GE:return "'>='";
+ case T_EQ:return "'='";
+ case T_NE:return "'<>'";
+ case T_DOTDOT:return "'..'";
+ case T_IDENT:return "identifier";
+ case T_INTCONST:return "integer literal";
+ case T_FLOATCONST:return "floating point literal";
+ case T_STRINGCONST:return "string literal";
+ case T_CSTRING:return "cstring tag";
+ case T_WSTRING:return "wstring tag";
+ case T_ARRAYDECL:return "array declaration";
+ case T_BADSTRINGCONST:return "malformed string literal";
+ case T_ADDASSIGN:return "add assign";
+ case T_SUBASSIGN:return "subtract assign";
+ case T_MULASSIGN:return "multiply assign";
+ case T_DIVASSIGN:return "divide assign";
+ case T_MODASSIGN:return "remainder assign";
+ case T_ORASSIGN:return "or assign";
+ case T_ANDASSIGN:return "and assign";
+ case T_XORASSIGN:return "exclusive or assign";
+ case T_SHLASSIGN:return "shift left assign";
+ case T_SHRASSIGN:return "shift right assign";
+ case T_SARASSIGN:return "Shift arithmetic right assign";
+ }
+ TokeMap::iterator it;
+ for( it=_tokes.begin();it!=_tokes.end();++it ){
+ if( n==it->second ) return it->first;
+ }
+ if( isgraph(n) ){
+ char c=n;
+ return "'"+string(&c,1)+"'";
+ }
+ char buf[8];
+ sprintf( buf,"%i",n );
+ return "<chr:"+string(buf)+">";
+}
--- /dev/null
+
+#ifndef TOKER_H
+#define TOKER_H
+
+struct Toke{
+ int toke;
+ int begin,end;
+
+ Toke():toke(0),begin(0),end(0){}
+ Toke( int n,int b,int e ):toke(n),begin(b),end(e){}
+};
+
+struct Toker{
+ FILE* fh;
+
+ enum{
+ UNK=0,LATIN1=1,UTF8=2,UTF16BE=3,UTF16LE=4
+ };
+ Toke curr_toke;
+ int toke_index;
+ int encoding;
+ vector<char> line;
+ vector<bchar_t> wline;
+ vector<Toke> tokes;
+
+ int line_num;
+ string file_name;
+
+ Toker( string file );
+ void close();
+
+ int curr();
+ int next();
+ string text();
+ bstring wtext();
+ int peek( int n );
+ void nextLine();
+ int tgetc();
+
+ string sourceFile();
+ string sourceInfo();
+
+ static string toString( int n );
+};
+
+enum{
+ T_NOP=0x80000000,
+
+ //non-ident
+ T_DOTDOT,
+
+ T_ARRAYDECL,
+
+ T_LT,T_EQ,T_GT,T_LE,T_GE,T_NE,
+
+ T_IDENT,T_INTCONST,T_FLOATCONST,T_STRINGCONST,T_BADSTRINGCONST,T_CSTRING,T_WSTRING,
+
+ //ident
+ T_STRICT,T_SUPERSTRICT,T_MODULE,T_FRAMEWORK,T_IMPORT,T_MODULEINFO,
+
+ T_DEFDATA,T_READDATA,T_RESTOREDATA,
+
+ T_REM,T_ENDREM,
+
+ T_TRY,T_CATCH,T_ENDTRY,T_THROW,T_GOTO,
+
+ T_TRUE,T_FALSE,T_PI,
+
+ T_BYTE,T_SHORT,T_INT,T_LONG,T_FLOAT,T_DOUBLE,T_OBJECT,T_STRING,
+
+ T_VAR,T_PTR,T_VARPTR,
+
+ T_CHR,
+ T_LEN,T_ASC,T_SIZEOF,
+
+ T_SGN,
+ T_ABS,T_MIN,T_MAX,T_MOD,
+ T_SHL,T_SHR,T_SAR,
+ T_NOT,T_AND,T_OR,
+
+ T_ADDASSIGN,T_SUBASSIGN,T_MULASSIGN,T_DIVASSIGN,T_MODASSIGN,
+ T_ORASSIGN,T_ANDASSIGN,T_XORASSIGN,T_SHLASSIGN,T_SHRASSIGN,T_SARASSIGN,
+
+ T_RETURN,T_LOCAL,T_GLOBAL,T_CONST,T_FIELD,T_ALIAS,T_END,
+
+ T_TYPE,T_ENDTYPE,T_EXTENDS,
+
+ T_METHOD,T_ENDMETHOD,T_ABSTRACT,T_FINAL,
+
+ T_FUNCTION,T_ENDFUNCTION,
+
+ T_NEW,T_RELEASE,T_DELETE,
+
+ T_NULL,T_SELF,T_SUPER,
+
+ T_INCBIN,T_INCBINPTR,T_INCBINLEN,
+
+ T_INCLUDE,T_EXTERN,T_ENDEXTERN,
+
+ T_PUBLIC,T_PRIVATE,
+
+ T_IF,T_THEN,T_ELSE,T_ELSEIF,T_ENDIF,
+
+ T_FOR,T_TO,T_STEP,T_NEXT,T_EACHIN,
+
+ T_WHILE,T_WEND,
+
+ T_REPEAT,T_UNTIL,T_FOREVER,
+
+ T_SELECT,T_CASE,T__DEFAULT,T_ENDSELECT,
+
+ T_EXIT,T_CONTINUE,
+
+ T_ASSERT,
+
+ T_NODEBUG
+};
+
+#endif
--- /dev/null
+
+#include "std.h"
+#include "decl.h"
+
+using namespace CG;
+
+static vector<ClassType*> _classTypes;
+static vector<ObjectType*> _objectTypes;
+static vector<PtrType*> _ptrTypes;
+
+IntType *Type::int8;
+IntType *Type::int16;
+IntType *Type::int32;
+IntType *Type::int64;
+FloatType *Type::float32;
+FloatType *Type::float64;
+CStringType *Type::c_string;
+WStringType *Type::w_string;
+PtrType *Type::bytePtr;
+NullType *Type::null;
+ModuleType *Type::blitzModule;
+ObjectType *Type::objectObject;
+StringType *Type::stringObject;
+Val *Type::objectClass,*Type::stringClass,*Type::arrayClass;
+
+void Type::createTypes(){
+
+ int8=new IntType(1);
+ int16=new IntType(2);
+ int32=new IntType(4);
+ int64=new IntType(8);
+ float32=new FloatType(4);
+ float64=new FloatType(8);
+ c_string=new CStringType();
+ w_string=new WStringType();
+ bytePtr=new PtrType(new IntType(1));
+ null=new NullType();
+
+ objectClass=new Val((Type*)0,(CGExp*)0);
+ objectObject=new ObjectType(0);
+ objectObject->ident="Object";
+ objectObject->class_val=objectClass;
+
+ stringClass=new Val((Type*)0,(CGExp*)0);
+ stringObject=new StringType(0);
+ stringObject->ident="String";
+ stringObject->class_val=stringClass;
+
+ arrayClass=new Val((Type*)0,(CGExp*)0);
+
+ blitzModule=new ModuleType();
+}
+
+void Type::resolveTypes(){
+ int k;
+ for( k=0;k<_classTypes.size();++k ) _classTypes[k]->resolve();
+ for( k=0;k<_objectTypes.size();++k ) _objectTypes[k]->resolve();
+ for( k=0;k<_ptrTypes.size();++k ) _ptrTypes[k]->resolve();
+}
+
+//********************* Type **********************
+Type::~Type(){
+}
+NumericType *Type::numericType(){
+ return 0;
+}
+IntType *Type::intType(){
+ return 0;
+}
+FloatType *Type::floatType(){
+ return 0;
+}
+StringType *Type::stringType(){
+ return 0;
+}
+CStringType *Type::cstringType(){
+ return 0;
+}
+WStringType *Type::wstringType(){
+ return 0;
+}
+ArrayType *Type::arrayType(){
+ return 0;
+}
+ClassType *Type::classType(){
+ return 0;
+}
+ObjectType *Type::objectType(){
+ return 0;
+}
+ObjectType *Type::exObjectType(){
+ return 0;
+}
+FunType *Type::funType(){
+ return 0;
+}
+PtrType *Type::ptrType(){
+ return 0;
+}
+VarType *Type::varType(){
+ return 0;
+}
+RefType *Type::refType(){
+ return 0;
+}
+NullType *Type::nullType(){
+ return 0;
+}
+ModuleType *Type::moduleType(){
+ return 0;
+}
+string Type::encoding(){
+ return "?";
+}
+string Type::toString(){
+ return "<void>";
+}
+bool Type::equals( Type *ty ){
+ return false;
+}
+bool Type::extends( Type *ty ){
+ return equals(ty);
+}
+int Type::size(){
+ switch( cgType() ){
+ case CG_VOID:return 0;
+ case CG_INT8:return 1;
+ case CG_INT16:return 2;
+ case CG_INT32:return 4;
+ case CG_INT64:return 8;
+ case CG_FLOAT32:return 4;
+ case CG_FLOAT64:return 8;
+ case CG_PTR:return 4;
+ }
+ assert(0);
+ return 0;
+}
+int Type::cgType(){
+ switch( encoding()[0] ){
+ case '?':return CG_VOID;
+ case 'b':return CG_INT8;
+ case 's':return CG_INT16;
+ case 'i':return CG_INT32;
+ case 'l':return CG_INT64;
+ case 'f':return CG_FLOAT32;
+ case 'd':return CG_FLOAT64;
+ }
+ return CG_PTR;
+}
+PtrType *Type::ptrType( string valEncoding ){
+ PtrType *p=ptrType();
+ return (p && p->val_type->encoding()==valEncoding) ? p : 0;
+}
+
+//****************** NumericType ******************
+NumericType::NumericType( int sz,bool fp ){
+ switch( sz ){
+ case 1:assert(!fp);_encoding="b";break;
+ case 2:assert(!fp);_encoding="s";break;
+ case 4:_encoding=fp ? "f" : "i";break;
+ case 8:_encoding=fp ? "d" : "l";break;
+ default:assert(0);
+ }
+}
+
+NumericType *NumericType::numericType(){
+ return this;
+}
+
+string NumericType::encoding(){
+ return _encoding;
+}
+
+string NumericType::toString(){
+ switch( encoding()[0] ){
+ case 'b':return "Byte";
+ case 's':return "Short";
+ case 'i':return "Int";
+ case 'l':return "Long";
+ case 'f':return "Float";
+ case 'd':return "Double";
+ default:assert(0);
+ }
+ return "";
+}
+
+bool NumericType::equals( Type *ty ){
+ NumericType *t=ty->numericType();
+ return t && encoding()==t->encoding();
+}
+
+//******************** IntType ********************
+IntType *IntType::intType(){
+ return this;
+}
+
+//******************* FloatType *******************
+FloatType *FloatType::floatType(){
+ return this;
+}
+
+//***************** CStringType *******************
+CStringType *CStringType::cstringType(){
+ return this;
+}
+
+string CStringType::encoding(){
+ return "z";
+}
+
+string CStringType::toString(){
+ return "CString";
+}
+
+bool CStringType::equals( Type *ty ){
+ return ty->cstringType() ? true : false;
+}
+
+//***************** WStringType *******************
+WStringType *WStringType::wstringType(){
+ return this;
+}
+
+string WStringType::encoding(){
+ return "w";
+}
+
+string WStringType::toString(){
+ return "WString";
+}
+
+bool WStringType::equals( Type *ty ){
+ return ty->wstringType() ? true : false;
+}
+
+//******************* StringType ******************
+StringType::StringType( Val *clas ):ObjectType(clas){
+}
+
+StringType *StringType::stringType(){
+ return this;
+}
+
+string StringType::encoding(){
+ return "$";
+}
+
+string StringType::toString(){
+ return "String";
+}
+
+bool StringType::equals( Type *ty ){
+ return ty->stringType() ? true : false;
+}
+
+//****************** ArrayType ********************
+ArrayType::ArrayType( Type *ty,int n ):ObjectType(arrayClass),element_type(ty),dims(n){
+}
+
+ArrayType *ArrayType::arrayType(){
+ return this;
+}
+
+string ArrayType::encoding(){
+ return "["+string(dims-1,',')+"]"+element_type->encoding();
+}
+
+string ArrayType::toString(){
+ return element_type->toString()+" Array";
+}
+
+bool ArrayType::equals( Type *ty ){
+ ArrayType *t=ty->arrayType();
+ return t && dims==t->dims && element_type->equals(t->element_type);
+}
+
+bool ArrayType::extends( Type *ty ){
+ ArrayType *t=ty->arrayType();
+ if( !t ) return ObjectType::extends( ty );
+ return t && dims==t->dims && element_type->extends(t->element_type);
+}
+
+//****************** ClassType ********************
+ClassType::ClassType( string supername,Scope *sc,int attrs ):
+super_name(supername),scope(sc),attrs(attrs),
+sizeof_fields(0),sizeof_vtable(0),super_val(0),super_class(0),resolved(0){
+ sourceinfo=source_info;
+ _classTypes.push_back(this);
+}
+
+void ClassType::resolve(){
+ if( resolved==1 ) return;
+ source_info=sourceinfo;
+ if( resolved==-1 ) fail( "Cyclic type dependancy" );
+ resolved=-1;
+
+ //resolve super
+ if( super_name.size() ){
+ if( super_val=scope->findTypeIdent( super_name ) ){
+ super_class=super_val->type->classType();
+ }
+ if( !super_class ) badty( super_name );
+ super_class->resolve();
+ if( super_class->attrs & ClassType::FINAL ) fail( "Final types cannot be extended" );
+ if( (attrs & ClassType::EXTERN) && !(super_class->attrs & ClassType::EXTERN) ) fail( "Extern types can only extends other extern types" );
+ if( (super_class->attrs & ClassType::EXTERN) && !(attrs & ClassType::EXTERN) ) fail( "Extern types can only be extended by other extern types" );
+ sizeof_fields=super_class->sizeof_fields;
+ sizeof_vtable=super_class->sizeof_vtable;
+ }else if( attrs & EXTERN ){
+ sizeof_fields=4;
+ sizeof_vtable=0;
+ }else{
+ sizeof_fields=8;
+ sizeof_vtable=16;
+ }
+
+ //resolve fields
+ int k;
+ for( k=0;k<fields.size();++k ){
+ Decl *d=fields[k];
+ Type *type=d->val->type;
+
+ int sz=type->size();
+ sizeof_fields=(sizeof_fields+sz-1)/sz*sz;
+
+ CGExp *e=mem( type->cgType(),tmp(CG_PTR,"@self"),sizeof_fields );
+
+ Decl *t=new Decl( d->ident,type,e );
+ t->setMetaData( d->meta );
+
+ decls.push_back( t );
+ sizeof_fields+=sz;
+ }
+
+ //resolve methods
+ for( k=0;k<methods.size();++k ){
+ Decl *d=methods[k];
+ FunType *type=d->val->type->funType();
+
+ CGExp *e;
+ Val *v=findSuperMethod(d->ident);
+
+ if( (attrs & FINAL) || (type->attrs & FunType::FINAL) ){
+ e=d->val->cg_exp;
+ if( type->method() ) e=vfn( e,tmp(CG_PTR,"@self") );
+ if( !v ) sizeof_vtable+=4;
+ }else if( v ){
+ e=v->cg_exp;
+ }else{
+ e=mem( CG_PTR,tmp(CG_PTR,"@type"),sizeof_vtable );
+ if( type->method() ) e=vfn( e,tmp(CG_PTR,"@self") );
+ sizeof_vtable+=4;
+ }
+
+ Decl *t=new Decl( d->ident,type,e );
+ t->setMetaData( d->meta );
+
+ decls.push_back( t );
+ }
+
+ resolved=1;
+}
+
+ClassType *ClassType::classType(){
+ return this;
+}
+
+Val *ClassType::superVal(){
+ return super_val;
+}
+
+ClassType *ClassType::superClass(){
+ return super_class;
+}
+
+string ClassType::encoding(){
+ return "^";
+}
+
+string ClassType::toString(){
+ return "Type";
+}
+
+bool ClassType::equals( Type *ty ){
+ return this==ty->classType();
+}
+
+bool ClassType::extends( Type *ty ){
+ ClassType *c=ty->classType();
+ if( !c ) return false;
+ ClassType *t;
+ for( t=this;t;t=t->super_class ){
+ if( t==ty ) return true;
+ }
+ return false;
+}
+
+Val *ClassType::find( string id ){
+ ClassType *t;
+ for( t=this;t;t=t->superClass() ){
+ Val *v=t->decls.find(id);
+ if( v && !v->countTmps( "@self" ) ) return v;
+ }
+ return 0;
+}
+
+Val *ClassType::findMethod( string id ){
+ ClassType *t;
+ for( t=this;t;t=t->super_class ){
+ if( t->methods.find(id) ) return t->decls.find(id);
+ }
+ return 0;
+}
+
+Val *ClassType::findSuperMethod( string id ){
+ return super_class ? super_class->findMethod( id ) : 0;
+}
+
+//****************** ObjectType *******************
+ObjectType::ObjectType( Val *clas ):ident("<unknown>"),scope(0),class_val(clas){
+}
+
+ObjectType::ObjectType( string id,Scope *sc ):ident(id),scope(sc),class_val(0){
+ sourceinfo=source_info;
+ _objectTypes.push_back( this );
+}
+
+ObjectType *ObjectType::objectType(){
+ if( objectClass()->attrs & ClassType::EXTERN ) return 0;
+ return this;
+}
+
+ObjectType *ObjectType::exObjectType(){
+ if( objectClass()->attrs & ClassType::EXTERN ) return this;
+ return 0;
+}
+
+void ObjectType::resolve(){
+ if( class_val ) return;
+
+ source_info=sourceinfo;
+
+ class_val=scope->findTypeIdent( ident );
+
+ if( !class_val ) badid( ident );
+
+ if( !class_val->type->classType() ) fail( "expecting type name" );
+}
+
+string ObjectType::encoding(){
+// if( objectClass()->attrs & ClassType::EXTERN ) return "?"+ident;
+ return ":"+ident;
+}
+
+string ObjectType::toString(){
+ return ident;
+}
+
+bool ObjectType::equals( Type *ty ){
+ ObjectType *o=objectType() ? ty->objectType() : ty->exObjectType();
+ return o ? objectClass()==o->objectClass() : false;
+}
+
+bool ObjectType::extends( Type *ty ){
+ ObjectType *o=objectType() ? ty->objectType() : ty->exObjectType();
+ return o && objectClass()->extends(o->objectClass());
+}
+
+Val *ObjectType::find( string id ){
+ ClassType *t;
+ for( t=objectClass();t;t=t->superClass() ){
+ if( Val *v=t->decls.find(id) ) return v;
+ }
+ return 0;
+}
+
+ClassType *ObjectType::objectClass(){
+ return class_val->type->classType();
+}
+
+//******************** FunType ********************
+FunType::FunType( Type *ty,int attrs ):return_type(ty),attrs(attrs),call_conv(CG_CDECL){
+}
+
+FunType *FunType::funType(){
+ return this;
+}
+
+string FunType::encoding(){
+ string t="(";
+ for( int k=0;k<args.size();++k ){
+ if( k ) t+=",";
+ t+=args[k]->val->type->encoding();
+ }
+ return t+")"+return_type->encoding();
+}
+
+string FunType::toString(){
+ string t=return_type->toString()+"(";
+ for( int k=0;k<args.size();++k ){
+ if( k ) t+=",";
+ t+=args[k]->val->type->toString();
+ }
+ return t+")";
+}
+
+bool FunType::equals( Type *ty ){
+ FunType *f=ty->funType();
+ if( !f ) return false;
+
+ if( method()!=f->method() || args.size()!=f->args.size() ) return false;
+
+ if( !return_type->equals(f->return_type) ) return false;
+
+ for( int k=0;k<args.size();++k ){
+ if( !args[k]->val->type->equals(f->args[k]->val->type) ) return false;
+ }
+
+ return true;
+}
+
+bool FunType::extends( Type *ty ){
+ FunType *f=ty->funType();
+ if( !f) return false;
+
+ if( method()!=f->method() || args.size()!=f->args.size() ) return false;
+
+ if( ObjectType *t=return_type->objectType() ){
+ ObjectType *p=f->return_type->objectType();
+ if( !p || !t->objectClass()->extends(p->objectClass()) ) return false;
+ }else{
+ if( !return_type->equals(f->return_type) ) return false;
+ }
+
+ for( int k=0;k<args.size();++k ){
+ if( !args[k]->val->type->equals(f->args[k]->val->type) ) return false;
+ }
+ return true;
+}
+
+bool FunType::method(){
+ return !!(attrs & METHOD);
+}
+
+//******************** PtrType ********************
+PtrType::PtrType( Type *ty ):val_type(ty){
+ _ptrTypes.push_back( this );
+ sourceinfo=source_info;
+}
+
+PtrType *PtrType::ptrType(){
+ return this;
+}
+
+void PtrType::resolve(){
+ source_info=sourceinfo;
+ if( val_type->ptrType() || val_type->numericType() || val_type->exObjectType() ) return;
+ fail( "Illegal pointer type" );
+}
+
+string PtrType::encoding(){
+ return "*"+val_type->encoding();
+}
+
+string PtrType::toString(){
+ return val_type->toString()+ " Ptr";
+}
+
+bool PtrType::equals( Type *ty ){
+ PtrType *t=ty->ptrType();
+ return t && val_type->equals(t->val_type);
+}
+
+//******************** VarType ********************
+VarType *VarType::varType(){
+ return this;
+}
+
+string VarType::encoding(){
+ return "*"+val_type->encoding();
+}
+
+string VarType::toString(){
+ return val_type->toString()+" Var";
+}
+
+bool VarType::equals( Type *ty ){
+ VarType *t=ty->varType();
+ return t && val_type->equals(t->val_type);
+}
+
+//******************** AliasType ********************
+AliasType::AliasType( Type *ty ):val_type(ty){
+}
+
+NumericType *AliasType::numericType(){
+ return val_type->numericType();
+}
+
+IntType *AliasType::intType(){
+ return val_type->intType();
+}
+
+FloatType *AliasType::floatType(){
+ return val_type->floatType();
+}
+
+ClassType *AliasType::classType(){
+ return val_type->classType();
+}
+
+ObjectType *AliasType::objectType(){
+ return val_type->objectType();
+}
+
+ObjectType *AliasType::exObjectType(){
+ return val_type->exObjectType();
+}
+
+StringType *AliasType::stringType(){
+ return val_type->stringType();
+}
+
+ArrayType *AliasType::arrayType(){
+ return val_type->arrayType();
+}
+
+FunType *AliasType::funType(){
+ return val_type->funType();
+}
+
+PtrType *AliasType::ptrType(){
+ return val_type->ptrType();
+}
+
+ModuleType *AliasType::moduleType(){
+ return val_type->moduleType();
+}
+
+string AliasType::encoding(){
+ return val_type->encoding();
+}
+
+string AliasType::toString(){
+ return val_type->toString();
+}
+
+bool AliasType::equals( Type *ty ){
+ return val_type->equals(ty);
+}
+
+bool AliasType::extends( Type *ty ){
+ return val_type->extends(ty);
+}
+
+Val *AliasType::find( string id ){
+ return val_type->find(id);
+}
+
+//***************** Reference Type ****************
+RefType *RefType::refType(){
+ return this;
+}
+
+//***************** Null Type *********************
+NullType *NullType::nullType(){
+ return this;
+}
+
+string NullType::toString(){
+ return "null";
+}
+
+bool NullType::equals( Type *ty ){
+ return !!ty->nullType();
+}
+
+//***************** Module Type *******************
+ModuleType *ModuleType::moduleType(){
+ return this;
+}
+
+string ModuleType::toString(){
+ return "module";
+}
+
+bool ModuleType::equals( Type *ty ){
+ return this==ty;
+}
+
+Val *ModuleType::find( string id ){
+ return decls.find(id);
+}
--- /dev/null
+
+#ifndef TYPE_H
+#define TYPE_H
+
+#include "scope.h"
+#include "declseq.h"
+
+struct Val;
+
+/*
+
+Runtime type Encoding:
+
+b=byte
+s=short
+i=int
+f=float
+d=double
+z=cstring
+$=string
+[]<type>=array
+^<ident>.<ident>=class
+:<ident>.<ident>=object
+(<type>,...)<type>=function
+*<type>=pointer
+
+*/
+
+struct NumericType;
+struct IntType;
+struct FloatType;
+struct StringType;
+struct CStringType;
+struct WStringType;
+struct ArrayType;
+struct ClassType;
+struct ObjectType;
+struct FunType;
+struct PtrType;
+struct VarType;
+struct RefType;
+struct NullType;
+struct ModuleType;
+
+struct Type : public Scope{
+ virtual ~Type();
+
+ virtual NumericType*numericType();
+ virtual IntType* intType();
+ virtual FloatType* floatType();
+ virtual StringType* stringType();
+ virtual CStringType*cstringType();
+ virtual WStringType*wstringType();
+ virtual ClassType* classType();
+ virtual ObjectType* objectType();
+ virtual ObjectType* exObjectType();
+ virtual ArrayType* arrayType();
+ virtual FunType* funType();
+
+ virtual PtrType* ptrType();
+ virtual VarType* varType();
+ virtual RefType* refType();
+ virtual NullType* nullType();
+ virtual ModuleType* moduleType();
+
+ virtual string encoding();
+ virtual string toString();
+ virtual bool equals( Type *ty );
+ virtual bool extends( Type *ty );
+
+ int size();
+ int cgType();
+ PtrType* ptrType( string valEncoding );
+
+ static void createTypes();
+ static void resolveTypes();
+
+ static IntType *int8,*int16,*int32,*int64;
+ static FloatType *float32,*float64;
+ static CStringType *c_string;
+ static WStringType *w_string;
+ static PtrType *bytePtr;
+ static NullType *null;
+ static ModuleType *blitzModule;
+ static ObjectType *objectObject;
+ static StringType *stringObject;
+ static Val *objectClass,*stringClass,*arrayClass;
+};
+
+struct NumericType : public Type{
+ string _encoding;
+
+ NumericType( int sz,bool fp );
+
+ NumericType *numericType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct IntType : public NumericType{
+ IntType( int sz ):NumericType( sz,false ){}
+
+ IntType *intType();
+};
+
+struct FloatType : public NumericType{
+ FloatType( int sz ):NumericType( sz,true ){}
+
+ FloatType *floatType();
+};
+
+struct CStringType : public Type{
+ CStringType *cstringType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct WStringType : public Type{
+ WStringType *wstringType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct ClassType : public Type{
+ enum{
+ ABSTRACT=1,FINAL=2,EXTERN=4,PRIVATE=8
+ };
+
+ string super_name;
+ Scope* scope;
+ DeclSeq decls,fields,methods;
+ int attrs,sizeof_fields,sizeof_vtable;
+
+ ClassType( string supername,Scope *sc,int attrs=0 );
+
+ ClassType*classType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+ bool extends( Type *ty );
+ Val* find( string id );
+
+ Val* findMethod( string id );
+ Val* findSuperMethod( string id );
+
+ void resolve();
+
+ Val* superVal();
+
+ ClassType*superClass();
+
+private:
+ int resolved;
+ Val* super_val;
+ ClassType*super_class;
+ string sourceinfo;
+};
+
+struct ObjectType : public Type{
+ string ident;
+ Scope *scope;
+ Val *class_val;
+ string sourceinfo;
+
+ ObjectType( Val *clas );
+ ObjectType( string id,Scope *sc );
+
+ ObjectType *objectType();
+ ObjectType *exObjectType();
+
+ void resolve();
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+ bool extends( Type *ty );
+ Val* find( string id );
+
+ Val* classVal();
+ ClassType *objectClass();
+};
+
+struct StringType : public ObjectType{
+
+ StringType( Val *clas );
+
+ StringType *stringType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct ArrayType : public ObjectType{
+ Type *element_type;
+ int dims;
+
+ ArrayType( Type *ty,int n );
+
+ ArrayType *arrayType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+ bool extends( Type *ty );
+};
+
+struct FunType : public Type{
+ enum{
+ ABSTRACT=1,FINAL=2,METHOD=4,VOIDFUN=8
+ };
+ DeclSeq args;
+ Type *return_type;
+ int attrs,call_conv;
+
+ FunType( Type *ty,int at=0 );
+
+ FunType *funType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+ bool extends( Type *ty );
+ bool method();
+};
+
+struct PtrType : public Type{
+ Type *val_type;
+ string sourceinfo;
+
+ PtrType( Type *ty );
+
+ PtrType *ptrType();
+
+ void resolve();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct VarType : public Type{
+ Type *val_type;
+
+ VarType( Type *ty ):val_type(ty){}
+
+ VarType *varType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct AliasType : public Type{
+ Type *val_type;
+
+ AliasType( Type *ty );
+
+ NumericType*numericType();
+ IntType* intType();
+ FloatType* floatType();
+ StringType* stringType();
+ ClassType* classType();
+ ObjectType* objectType();
+ ObjectType* exObjectType();
+ ArrayType* arrayType();
+ FunType* funType();
+ PtrType* ptrType();
+ ModuleType* moduleType();
+
+ string encoding();
+ string toString();
+ bool equals( Type *ty );
+ bool extends( Type *ty );
+ Val* find( string id );
+};
+
+struct RefType : public AliasType{
+ enum{
+ VARPARAM=1
+ };
+ int attrs;
+
+ RefType( Type *ty,int at=0 ):AliasType(ty),attrs(at){}
+
+ RefType* refType();
+};
+
+struct NullType : public Type{
+
+ NullType *nullType();
+
+ string toString();
+ bool equals( Type *ty );
+};
+
+struct ModuleType : public Type{
+ DeclSeq decls;
+
+ ModuleType* moduleType();
+
+ string toString();
+ bool equals( Type *ty );
+ Val* find( string id );
+};
+
+#endif
--- /dev/null
+
+#include "std.h"
+#include "val.h"
+#include "block.h"
+
+using namespace CG;
+
+static CGLit *literal( CGExp *e ){
+ if( CGLit *t=e->lit() ) return t;
+ if( CGDat *t=e->dat() ){
+ if( t->exps.size()==3 ) return t->exps[2]->lit();
+ }
+ if( CGSym *t=e->sym() ){
+ if( t->value=="bbEmptyString" ) return lit(bstring());
+ }
+ return 0;
+}
+
+//********************* Val ***********************
+Val::Val( int n,Type *ty ):type(ty){
+ assert( ty->intType() );
+ switch( ty->cgType() ){
+ case CG_INT8:n&=0xff;break;
+ case CG_INT16:n&=0xffff;break;
+ }
+ cg_exp=ty->cgType()==CG_INT64 ? lit( int64(n) ) : lit( int(n) );
+}
+
+Val::Val( int64 n,Type *ty ):type(ty){
+ assert( ty->intType() );
+ switch( ty->cgType() ){
+ case CG_INT8 :n&=int64(0xff);break;
+ case CG_INT16:n&=int64(0xffff);break;
+ case CG_INT32:n&=int64(0xffffffff);break;
+ }
+ cg_exp=ty->cgType()==CG_INT64 ? lit( int64(n) ) : lit( int(n) );
+}
+
+Val::Val( float n,Type *ty ):type(ty){
+ assert( ty->floatType() );
+ cg_exp=ty->cgType()==CG_FLOAT64 ? lit( double(n) ) : lit( float(n) );
+}
+
+Val::Val( double n,Type *ty ):type(ty){
+ assert( ty->floatType() );
+ cg_exp=ty->cgType()==CG_FLOAT64 ? lit( double(n) ) : lit( float(n) );
+}
+
+Val::Val( bstring t ):type(Type::stringObject){
+ cg_exp=genBBString(t);
+}
+
+Val::Val( const char *t ):type(Type::c_string){
+ cg_exp=genCString(t);
+}
+
+Val::Val( Type *t,CGExp *e ):type(t),cg_exp(e){
+}
+
+Val::~Val(){
+}
+
+CGExp *Val::constant(){
+ return cg_exp->lit() || cg_exp->sym() ? cg_exp : 0;
+}
+
+int64 Val::intValue(){
+ CGLit *t=literal( cg_exp );
+ assert(t);
+ switch( t->type ){
+ case CG_INT8:case CG_INT16:return t->int_value;
+ case CG_INT32:case CG_INT64:return t->int_value;
+ case CG_FLOAT32:case CG_FLOAT64:return (int64)t->float_value;
+ case CG_BSTRING:return toint(tostring(t->string_value));
+ }
+ assert(0);
+ return 0;
+}
+
+double Val::floatValue(){
+ CGLit *t=literal( cg_exp );
+ assert(t);
+ switch( t->type ){
+ case CG_INT8:case CG_INT16:return t->int_value;
+ case CG_INT32:case CG_INT64:return t->int_value;
+ case CG_FLOAT32:case CG_FLOAT64:return t->float_value;
+ case CG_BSTRING:return tofloat(tostring(t->string_value));
+ }
+ assert(0);
+ return 0;
+}
+
+bstring Val::stringValue(){
+ CGLit *t=literal( cg_exp );
+ assert(t);
+ switch( t->type ){
+ case CG_INT8:return tobstring(fromint(t->int_value));
+ case CG_INT16:return tobstring(fromint(t->int_value));
+ case CG_INT32:return tobstring(fromint(t->int_value));
+ case CG_INT64:return tobstring(fromint(t->int_value));
+ case CG_FLOAT32:return tobstring(fromfloat(t->float_value));
+ case CG_FLOAT64:return tobstring(fromdouble(t->float_value));
+ case CG_BSTRING:return t->string_value;
+ }
+ assert(0);
+ return tobstring("");
+}
+
+Val *Val::cond(){
+ CGExp *e=0;
+
+ if( type->nullType() ){
+ e=lit0;
+ }else if( type->intType() ){
+ if( type->cgType()!=CG_INT64 ) return this;
+ e=scc(CG_NE,cg_exp,lit(int64(0)));
+ }else if( type->floatType() ){
+ if( constant() ) e=floatValue() ? lit1 : lit0;
+ else e=scc(CG_NE,cg_exp,type->size()==8 ? lit(0.0) : lit(0.0f));
+ }else if( type->stringType() ){
+ if( constant() ) e=stringValue().size() ? lit1 : lit0;
+ else e=mem(CG_INT32,cg_exp,8); //len of string
+ }else if( type->arrayType() ){
+ e=mem(CG_INT32,cg_exp,16); //len of array
+ }else if( type->objectType() ){
+ e=scc(CG_NE,cg_exp,sym("bbNullObject",CG_IMPORT));//cmp with null object
+ }else if( type->exObjectType() ){
+ e=scc(CG_NE,cg_exp,lit0); //cmp with 0
+ }else if( type->ptrType() ){
+ e=scc(CG_NE,cg_exp,lit0); //cmp with 0
+ }else if( FunType *f=type->funType() ){
+ if( !f->method() ){
+ e=scc(CG_NE,cg_exp,sym("brl_blitz_NullFunctionError",CG_IMPORT));
+ }
+ }
+
+ if( !e ) fail( "Unable to convert expression to conditional value" );
+
+ return new Val(Type::int32,e);
+}
+
+Type *Val::balance( Val *t ){
+ return balance( t->type );
+}
+
+Type *Val::balance( Type *y ){
+
+ Type *x=type;
+
+ if( x->intType() ){
+ if( y->intType() ) return (x->cgType()==CG_INT64 || y->cgType()==CG_INT64) ? Type::int64 : Type::int32;
+ if( y->floatType() ) return y;
+ if( y->stringType() ) return y;
+ if( y->objectType() ) return y;
+ if( y->classType() ) return y;
+ }else if( x->floatType() ){
+ if( y->intType() ) return x;
+ if( y->floatType() ) return (x->cgType()==CG_FLOAT64 || y->cgType()==CG_FLOAT64) ? Type::float64 : Type::float32;
+ if( y->stringType() ) return y;
+ if( y->classType() ) return y;
+ if( y->objectType() ) return y;
+ }else if( x->stringType() ){
+ if( y->intType() ) return x;
+ if( y->floatType() ) return x;
+ if( y->stringType() ) return x;
+ if( y->objectType() ) return y;
+ if( y->classType() ) return y;
+ }else if( FunType *p=x->funType() ){
+ if( FunType *q=y->funType() ){
+ if( p->extends(q) ) return y;
+ if( q->extends(p) ) return x;
+ }
+ }else if( ObjectType *p=x->objectType() ){
+ if( ObjectType *q=y->objectType() ){
+ if( p->extends(q) ) return y;
+ if( q->extends(p) ) return x;
+ }
+ }else if( ObjectType *p=x->exObjectType() ){
+ if( ObjectType *q=y->exObjectType() ){
+ if( p->extends(q) ) return y;
+ if( q->extends(p) ) return x;
+ }
+ }
+
+ if( x->nullType() ) return y;
+ if( y->nullType() ) return x;
+
+ fail( "Types '%s' and '%s' are unrelated",x->toString().c_str(),y->toString().c_str() );
+ return 0;
+}
+
+Val *Val::cast( Type *dst ){
+
+ //nop?
+ if( type->equals(dst) ) return this;
+ if( type->extends(dst) ) return new Val(dst,cg_exp);
+
+ //null casts...
+ if( type->nullType() ){
+ if( dst->intType() ) return new Val(0,dst);
+ if( dst->floatType() ) return new Val(0.0,dst);
+ if( dst->ptrType() ) return new Val(dst,lit0);
+ if( dst->cstringType() ) return new Val(dst,lit0);
+ if( dst->wstringType() ) return new Val(dst,lit0);
+ if( dst->stringType() ) return new Val(dst,sym("bbEmptyString",CG_IMPORT));
+ if( dst->arrayType() ) return new Val(dst,sym("bbEmptyArray",CG_IMPORT));
+ if( dst->objectType() ) return new Val(dst,sym("bbNullObject",CG_IMPORT));
+ if( dst->exObjectType() ) return new Val(dst,lit0);
+ if( dst->funType() ) return new Val(dst,sym("brl_blitz_NullFunctionError",CG_IMPORT));
+ fail( "Unable to cast 'Null' to '%s'",(dst->toString()).c_str() );
+ return 0;
+ }
+
+ int cg_ty=dst->cgType();
+
+ //literal conversions
+ if( constant() && type->numericType() ){
+ switch( cg_ty ){
+ case CG_INT8:return new Val( intValue(),Type::int8 );
+ case CG_INT16:return new Val( intValue(),Type::int16 );
+ case CG_INT32:return new Val( intValue(),Type::int32 );
+ case CG_INT64:return new Val( intValue(),Type::int64 );
+ case CG_FLOAT32:return new Val( floatValue(),Type::float32 );
+ case CG_FLOAT64:return new Val( floatValue(),Type::float64 );
+ default:if( dst->stringType() ) return new Val( stringValue() );
+ }
+ }
+
+ CGExp *e=0;
+
+ //standard type conversions
+ if( type->intType() ){
+ if( dst->intType() ){
+ e=cvt(cg_ty,cg_exp);
+ }else if( dst->floatType() ){
+ e=cvt(cg_ty,cg_exp);
+ }else if( dst->stringType() ){
+ if( type->cgType()==CG_INT64 ){
+ e=jsr(cg_ty,"bbStringFromLong",cg_exp);
+ }else{
+ e=jsr(cg_ty,"bbStringFromInt",cvt(CG_INT32,cg_exp));
+ }
+ }
+ }else if( type->floatType() ){
+ if( dst->intType() ){
+ e=cvt(cg_ty,cg_exp);
+ }else if( dst->floatType() ){
+ e=cvt(cg_ty,cg_exp);
+ }else if( dst->stringType() ){
+ if( type->cgType()==CG_FLOAT64 ){
+ e=jsr(cg_ty,"bbStringFromDouble",cg_exp );
+ }else{
+ e=jsr(cg_ty,"bbStringFromFloat",cg_exp );
+ }
+ }
+ }else if( type->stringType() ){
+ /*
+ if( dst->cstringType() ){
+ e=jsr(CG_PTR,"bbStringToCString",cg_exp);
+ }else if( dst->wstringType() ){
+ e=jsr(CG_PTR,"bbStringToWString",cg_exp);
+ }
+ */
+ }else if( type->cstringType() ){
+ /*
+ if( dst->stringType() ){
+ e=jsr(cg_ty,"bbStringFromCString",cg_exp);
+ }else if( dst->cstringType() ){
+ e=cg_exp;
+ }
+ */
+ }else if( type->wstringType() ){
+ /*
+ if( dst->stringType() ){
+ e=jsr(cg_ty,"bbStringFromWString",cg_exp);
+ }else if( dst->wstringType() ){
+ e=cg_exp;
+ }
+ */
+ }else if( ArrayType *src_ty=type->arrayType() ){
+ if( PtrType *dst_ty=dst->ptrType() ){
+ Type *val_ty=dst_ty->val_type;
+ if( val_ty->encoding()=="b" || val_ty->equals(src_ty->element_type) ){
+ e=cg_exp;
+ if( e->tmp() ){
+ e=mem(CG_PTR,lea(e),0);
+ }else if( !e->mem() ){
+ CGTmp *t=tmp(CG_PTR);
+ e=esq(mov(t,e),mem(CG_PTR,lea(t),0));
+ }
+ e=lea(mem(val_ty->cgType(),e,src_ty->dims*4+20));
+ }
+ }
+ }else if( ObjectType *src_ty=type->objectType() ){
+ if( PtrType *dst_ty=dst->ptrType() ){
+ if( dst_ty->val_type->encoding()=="b" ){
+ e=cg_exp;
+ if( e->tmp() ){
+ e=mem(CG_PTR,lea(e),0);
+ }else if( !e->mem() ){
+ CGTmp *t=tmp(CG_PTR);
+ e=esq(mov(t,e),mem(CG_PTR,lea(t),0));
+ }
+ e=lea(mem(CG_PTR,e,8));
+ }
+ }
+ }else if( ObjectType *src_ty=type->exObjectType() ){
+ if( PtrType *dst_ty=dst->ptrType() ){
+ if( dst_ty->val_type->encoding()=="b" ){
+ e=cg_exp;
+ }
+ }
+ }else if( PtrType *src_ty=type->ptrType() ){
+ if( PtrType *dst_ty=dst->ptrType() ){
+ if( dst_ty->val_type->equals(src_ty->val_type) || dst_ty->val_type->encoding()=="b" ){
+ e=cg_exp;
+ }
+ }else if( FunType *dst_ty=dst->funType() ){
+ if( src_ty->val_type->encoding()=="b" ){
+ //check for '0' func!
+ CGTmp *t=tmp(CG_PTR);
+ CGSym *p=sym();
+ CGStm *s=CG::seq(
+ mov(t,cg_exp),
+ bcc(CG_NE,t,lit0,p),
+ mov(t,sym("brl_blitz_NullFunctionError",CG_IMPORT)),
+ lab(p),
+ 0 );
+ e=esq(s,t);
+ }
+ }
+ }else if( FunType *src_ty=type->funType() ){
+ if( PtrType *dst_ty=dst->ptrType() ){
+ if( !src_ty->method() && dst_ty->val_type->encoding()=="b" ) e=cg_exp;
+ }
+ }
+
+ if( !e ) fail( "Unable to convert from '%s' to '%s'",type->toString().c_str(),dst->toString().c_str() );
+
+ return new Val(dst,e);
+}
+
+Val *Val::initCast( Type *dst ){
+ if( !strictMode && dst->cgType()==CG_INT32 ){
+ if( type->objectType() && !type->stringType() && !type->arrayType() ){
+ return new Val( dst,jsr(CG_INT32,"bbHandleFromObject",cg_exp) );
+ }
+ }
+ return cast( dst );
+}
+
+Val *Val::funArgCast( Type *dst,CGSeq *cleanup ){
+ //convert reference to var
+ if( VarType *var=dst->varType() ){
+ RefType *ref=type->refType();
+ if( !ref ) fail( "Expression for 'Var' parameter must be a variable" );
+ if( !ref->val_type->extends(var->val_type) ) fail( "Variable for 'Var' parameter is not of matching type" );
+ CGExp *e=lea(cg_exp);
+ if( !opt_threaded && var->val_type->objectType() && cg_exp->tmp() ){
+ CGMem *m=mem(CG_INT32,cg_exp,4);
+ e=esq(ati(m),e);
+ CGSym *l=sym();
+ cleanup->push_back( CG::seq(
+ atd(m,l),
+ eva(jsr(CG_INT32,"bbGCFree",cg_exp)),
+ lab(l),
+ 0) );
+ }
+ return new Val( dst,e );
+ }
+
+ //convert int32 to object
+ if( !strictMode && type->cgType()==CG_INT32 ){
+ if( dst->objectType() && !dst->stringType() && !dst->arrayType() ){
+ Val *v=new Val( Type::objectObject,jsr(CG_PTR,"bbHandleToObject",cg_exp) );
+ return v->explicitCast(dst);
+ }
+ }
+
+ //convert string to cstring/wstring
+ if( type->stringType() ){
+ CGExp *e=0;
+ if( dst->cstringType() || dst->ptrType("b") ){
+ e=jsr(CG_PTR,"bbStringToCString",cg_exp);
+ }else if( dst->wstringType() || dst->ptrType("s") ){
+ e=jsr(CG_PTR,"bbStringToWString",cg_exp);
+ }
+ if( e ){
+ CGTmp *t=tmp(CG_PTR);
+ e=esq(mov(t,e),t);
+ cleanup->push_back( eva(jsr(CG_INT32,"bbMemFree",t)) );
+ return new Val( dst,e );
+ }
+ }
+
+ return cast(dst);
+}
+
+Val *Val::explicitCast( Type *dst ){
+
+ if( type->nullType() ) return cast(dst);
+
+ if( type->equals(dst) ) return this;
+
+ int cg_ty=dst->cgType();
+
+ //literal conversions
+ if( constant() && type->stringType() ){
+ switch( cg_ty ){
+ case CG_INT8:return new Val( intValue(),Type::int8 );
+ case CG_INT16:return new Val( intValue(),Type::int16 );
+ case CG_INT32:return new Val( intValue(),Type::int32 );
+ case CG_INT64:return new Val( intValue(),Type::int64 );
+ case CG_FLOAT32:return new Val( floatValue(),Type::float32 );
+ case CG_FLOAT64:return new Val( floatValue(),Type::float64 );
+ }
+ }
+
+ CGExp *e=0;
+
+ if( type->ptrType() ){
+ if( dst->intType() ){
+ //ptr to int
+ e=cvt(cg_ty,cg_exp);
+ }else if( dst->ptrType() ){
+ //ptr to ptr
+ e=cg_exp;
+ }
+ }else if( type->intType() ){
+ if( dst->ptrType() ){
+ //int to ptr
+ e=cvt(cg_ty,cg_exp);
+ }
+ }else if( type->stringType() ){
+ if( dst->intType() ){
+ //string to int
+ if( cg_ty==CG_INT64 ){
+ e=jsr(cg_ty,CG_CDECL,vfn(sym("bbStringToLong",CG_IMPORT),cg_exp) );
+ }else{
+ e=cvt(cg_ty,jsr(CG_INT32,"bbStringToInt",cg_exp));
+ }
+ }else if( dst->floatType() ){
+ //string to float
+ if( cg_ty==CG_FLOAT64 ){
+ e=jsr(cg_ty,"bbStringToDouble",cg_exp );
+ }else{
+ e=jsr(cg_ty,"bbStringToFloat",cg_exp );
+ }
+ }
+ }else if( ObjectType *src_ty=type->objectType() ){
+ if( ObjectType *dst_ty=dst->objectType() ){
+ if( dst_ty->extends(src_ty) ){
+ if( ArrayType *arr_ty=dst->arrayType() ){
+ e=jsr(CG_PTR,"bbArrayCastFromObject",cg_exp,genCString(arr_ty->element_type->encoding()) );
+ }else{
+ e=jsr(CG_PTR,"bbObjectDowncast",cg_exp,dst_ty->class_val->cg_exp);
+ }
+ if( dst->stringType() || dst->arrayType() ){
+ CGSym *t=sym( (dst->stringType() ? "bbEmptyString" : "bbEmptyArray"),CG_IMPORT );
+ CGTmp *r=tmp(CG_PTR);
+ CGSym *l=sym();
+ CGStm *s=CG::seq(
+ mov(r,e),
+ bcc(CG_NE,r,sym("bbNullObject",CG_IMPORT),l),
+ mov(r,t),
+ lab(l),
+ 0 );
+ e=esq(s,r);
+ }
+ }
+ }
+ }else if( ObjectType *src_ty=type->exObjectType() ){
+ if( ObjectType *dst_ty=dst->exObjectType() ){
+ if( dst_ty->extends(src_ty) ){
+ e=cg_exp;
+ }
+ }
+ }
+
+ if( e ) return new Val( dst,e );
+
+ return cast(dst);
+}
+
+Val *Val::forEachCast( Type *dst ){
+
+ if( type->nullType() ) return cast(dst);
+
+ if( type->equals(dst) ) return this;
+
+ CGExp *e=0;
+ int cg_ty=dst->cgType();
+
+ if( ObjectType *src_ty=type->objectType() ){
+ if( ObjectType *dst_ty=dst->objectType() ){
+ if( dst_ty->extends(src_ty) ){
+ if( dst_ty->objectClass()->attrs & ClassType::EXTERN ){
+ e=cg_exp;
+ }else if( ArrayType *arr_ty=dst->arrayType() ){
+ e=jsr(CG_PTR,"bbArrayCastFromObject",cg_exp,genCString(arr_ty->element_type->encoding()) );
+ }else{
+ e=jsr(CG_PTR,"bbObjectDowncast",cg_exp,dst_ty->class_val->cg_exp);
+ }
+ }
+ }
+ }
+
+ if( e ) return new Val( dst,e );
+
+ return explicitCast( dst );
+}
+
+Val *Val::find( string id ){
+ Val *v=type->find(id);
+ if( !v ) return 0;
+
+ int n_self=v->countTmps("@self");
+ int n_type=v->countTmps("@type");
+ if( !n_self && !n_type ) return v;
+
+ CGExp *cg=cg_exp;
+
+ if( n_self && opt_debug && !type->stringType() && !type->arrayType() ){
+ cg=tmp(CG_PTR);
+
+ CGSym *q=sym();
+ CGStm *stms=CG::seq(
+ mov(cg,cg_exp),
+ bcc(CG_NE,cg,sym("bbNullObject",CG_IMPORT),q),
+ eva(jsr(CG_INT32,"brl_blitz_NullObjectError")),
+ lab(q),
+ 0 );
+ v=new Val(v->type,esq(stms,v->cg_exp));
+ }else if( n_self+n_type>1 ){
+ cg=tmp(CG_PTR);
+ v=new Val(v->type,esq(mov(cg,cg_exp),v->cg_exp));
+ }
+
+ if( type->objectType() || type->exObjectType() ){
+ if( n_self ) v=v->renameTmps( "@self",cg );
+ if( n_type ) v=v->renameTmps( "@type",mem(CG_PTR,cg,0) );
+ }else if( type->classType() ){
+ assert( !n_self );
+ if( n_type ) v=v->renameTmps( "@type",cg );
+ }else{
+ assert(0);
+ }
+
+ return v;
+}
+
+bool Val::refCounted(){
+ if( opt_threaded ) return false;
+ RefType *t=type->refType();
+ return t && t->objectType() && cg_exp->mem();
+}
+
+Val *Val::retain(){
+ if( opt_threaded ){
+ fail( "Internal error: Val::retain() invoked in threaded mode." );
+ }
+ CGTmp *p=tmp(CG_PTR);
+ CGMem *m=mem(CG_INT32,p,4);
+ CGStm *t=seq(
+ mov(p,cg_exp),
+ ati(m),
+ 0);
+ return new Val(type,esq(t,p));
+}
+
+CGStm *Val::release(){
+ if( opt_threaded ){
+ fail( "Internal error: Val::release() invoked in threaded mode." );
+ }
+ CGTmp *p=tmp(CG_PTR);
+ CGMem *m=mem(CG_INT32,p,4);
+ CGSym *q=sym();
+ CGStm *t=seq(
+ mov(p,cg_exp),
+ atd(m,q),
+ eva(jsr(CG_INT32,"bbGCFree",p)),
+ lab(q),
+ 0);
+ return t;
+}
+
+struct TmpCounter : public CGVisitor{
+ int n;
+ string ident;
+
+ TmpCounter( string id ):n(0),ident(id){
+ }
+
+ CGExp *visit( CGExp *e ){
+ if( CGTmp *t=e->tmp() ){
+ if( ident==t->ident ) ++n;
+ }
+ return e;
+ }
+};
+
+int Val::countTmps( string id ){
+ if( !cg_exp ) return 0;
+ TmpCounter cnt( id );
+ cg_exp->visit( cnt );
+ return cnt.n;
+}
+
+struct TmpRenamer : public CGVisitor{
+ string ident;
+ CGExp *cg_exp;
+
+ TmpRenamer( string id,CGExp *e ):ident(id),cg_exp(e){
+ }
+
+ CGExp *visit( CGExp *e ){
+ if( CGTmp *t=e->tmp() ){
+ if( ident==t->ident ) return cg_exp;
+ }
+ return e;
+ }
+};
+
+Val *Val::renameTmps( string id,CGExp *e ){
+ if( !cg_exp ) return this;
+ TmpRenamer ren( id,e );
+ CGExp *t=cg_exp->visit( ren );
+ return t==cg_exp ? this : new Val(type,t);
+}
+
+Val *Val::null( Type *ty ){
+ return (new Val(Type::null,0))->cast(ty);
+}
+
+//*********************** SuperVal *************************
+SuperVal::SuperVal( Val *v ):Val(v->type,v->cg_exp){
+}
+
+Val *SuperVal::find( string id ){
+
+ ObjectType *o=type->objectType();
+ ClassType *t=o ? o->objectClass() : type->classType();
+
+ assert(t);
+
+ Val *v=0;
+ bool method=false;
+
+ for( t=t->superClass();t;t=t->superClass() ){
+ v=t->methods.find(id);
+ if( !v ) continue;
+ method=v->type->funType()->method();
+ if( o || !method ) break;
+ v=0;
+ }
+
+ if( !v ) badid(id);
+
+ if( method ) v=new Val( v->type,vfn(v->cg_exp,cg_exp) );
+
+ return v;
+}
--- /dev/null
+
+#ifndef VAL_H
+#define VAL_H
+
+#include "type.h"
+#include "scope.h"
+
+struct Val : public Scope{
+ Type *type;
+ CGExp *cg_exp;
+
+ Val( int n,Type *ty=Type::int32 );
+ Val( int64 n,Type *ty=Type::int64 );
+ Val( float n,Type *ty=Type::float32 );
+ Val( double n,Type *ty=Type::float64 );
+
+ Val( bstring t );
+ Val( const char *t );
+ Val( Type *t,CGExp *e );
+ virtual ~Val();
+
+ CGExp* constant();
+
+ int64 intValue();
+ double floatValue();
+ bstring stringValue();
+
+ Val* cond();
+ Val* cast( Type *ty );
+ Val* initCast( Type *ty );
+ Val* funArgCast( Type *ty,CGSeq *cleanup );
+ Val* forEachCast( Type *ty );
+ Val* explicitCast( Type *ty );
+ Val* find( string id );
+
+ Type* balance( Val *t );
+ Type* balance( Type *t );
+
+ Val* retain();
+ CGStm* release();
+
+ bool refCounted();
+ int countTmps( string id );
+ Val* renameTmps( string id,CGExp *e );
+
+ static Val* null( Type *ty );
+};
+
+struct SuperVal : public Val{
+ SuperVal( Val *v );
+
+ Val* find( string id );
+};
+
+#endif
\ No newline at end of file