Added compiler src.
authorblitz-research <blitzmunter@gamil.com>
Wed, 22 Jan 2014 23:11:01 +0000 (12:11 +1300)
committerblitz-research <blitzmunter@gamil.com>
Wed, 22 Jan 2014 23:11:01 +0000 (12:11 +1300)
70 files changed:
_src/.gitignore [new file with mode: 0644]
_src/codegen/cgallocregs.cpp [new file with mode: 0644]
_src/codegen/cgallocregs.h [new file with mode: 0644]
_src/codegen/cgasm.cpp [new file with mode: 0644]
_src/codegen/cgasm.h [new file with mode: 0644]
_src/codegen/cgblock.cpp [new file with mode: 0644]
_src/codegen/cgblock.h [new file with mode: 0644]
_src/codegen/cgcode.cpp [new file with mode: 0644]
_src/codegen/cgcode.h [new file with mode: 0644]
_src/codegen/cgdebug.cpp [new file with mode: 0644]
_src/codegen/cgdebug.h [new file with mode: 0644]
_src/codegen/cgfixfp_x86.cpp [new file with mode: 0644]
_src/codegen/cgfixfp_x86.h [new file with mode: 0644]
_src/codegen/cgflow.cpp [new file with mode: 0644]
_src/codegen/cgflow.h [new file with mode: 0644]
_src/codegen/cgframe.cpp [new file with mode: 0644]
_src/codegen/cgframe.h [new file with mode: 0644]
_src/codegen/cgframe_ppc.cpp [new file with mode: 0644]
_src/codegen/cgframe_ppc.h [new file with mode: 0644]
_src/codegen/cgframe_x86.cpp [new file with mode: 0644]
_src/codegen/cgframe_x86.h [new file with mode: 0644]
_src/codegen/cgint64.cpp [new file with mode: 0644]
_src/codegen/cgint64.h [new file with mode: 0644]
_src/codegen/cgintset.cpp [new file with mode: 0644]
_src/codegen/cgintset.h [new file with mode: 0644]
_src/codegen/cgmodule.cpp [new file with mode: 0644]
_src/codegen/cgmodule.h [new file with mode: 0644]
_src/codegen/cgmodule_ppc.cpp [new file with mode: 0644]
_src/codegen/cgmodule_ppc.h [new file with mode: 0644]
_src/codegen/cgmodule_x86.cpp [new file with mode: 0644]
_src/codegen/cgmodule_x86.h [new file with mode: 0644]
_src/codegen/cgstd.h [new file with mode: 0644]
_src/codegen/cgutil.cpp [new file with mode: 0644]
_src/codegen/cgutil.h [new file with mode: 0644]
_src/codegen/codegen.cpp [new file with mode: 0644]
_src/codegen/codegen.h [new file with mode: 0644]
_src/compiler/bcc.cpp [new file with mode: 0644]
_src/compiler/block.cpp [new file with mode: 0644]
_src/compiler/block.h [new file with mode: 0644]
_src/compiler/config.cpp [new file with mode: 0644]
_src/compiler/config.h [new file with mode: 0644]
_src/compiler/config.h.bak [new file with mode: 0644]
_src/compiler/decl.cpp [new file with mode: 0644]
_src/compiler/decl.h [new file with mode: 0644]
_src/compiler/declseq.cpp [new file with mode: 0644]
_src/compiler/declseq.h [new file with mode: 0644]
_src/compiler/exp.cpp [new file with mode: 0644]
_src/compiler/exp.h [new file with mode: 0644]
_src/compiler/make.bat [new file with mode: 0644]
_src/compiler/module.cpp [new file with mode: 0644]
_src/compiler/module.h [new file with mode: 0644]
_src/compiler/output.cpp [new file with mode: 0644]
_src/compiler/output.h [new file with mode: 0644]
_src/compiler/parser.cpp [new file with mode: 0644]
_src/compiler/parser.h [new file with mode: 0644]
_src/compiler/scope.cpp [new file with mode: 0644]
_src/compiler/scope.h [new file with mode: 0644]
_src/compiler/std.cpp [new file with mode: 0644]
_src/compiler/std.h [new file with mode: 0644]
_src/compiler/stdutil.cpp [new file with mode: 0644]
_src/compiler/stdutil.h [new file with mode: 0644]
_src/compiler/stm.cpp [new file with mode: 0644]
_src/compiler/stm.h [new file with mode: 0644]
_src/compiler/toker.cpp [new file with mode: 0644]
_src/compiler/toker.cpp.bak [new file with mode: 0644]
_src/compiler/toker.h [new file with mode: 0644]
_src/compiler/type.cpp [new file with mode: 0644]
_src/compiler/type.h [new file with mode: 0644]
_src/compiler/val.cpp [new file with mode: 0644]
_src/compiler/val.h [new file with mode: 0644]

diff --git a/_src/.gitignore b/_src/.gitignore
new file mode 100644 (file)
index 0000000..aa21a79
--- /dev/null
@@ -0,0 +1,2 @@
+/old/*
+/setup/*
diff --git a/_src/codegen/cgallocregs.cpp b/_src/codegen/cgallocregs.cpp
new file mode 100644 (file)
index 0000000..baf1c50
--- /dev/null
@@ -0,0 +1,596 @@
+
+#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
+}
diff --git a/_src/codegen/cgallocregs.h b/_src/codegen/cgallocregs.h
new file mode 100644 (file)
index 0000000..4e690ea
--- /dev/null
@@ -0,0 +1,9 @@
+
+#ifndef CGALLOCREGS_H
+#define CGALLOCREGS_H
+
+#include "cgframe.h"
+
+void cgAllocRegs( CGFrame *frame );
+
+#endif
\ No newline at end of file
diff --git a/_src/codegen/cgasm.cpp b/_src/codegen/cgasm.cpp
new file mode 100644 (file)
index 0000000..c8bdad5
--- /dev/null
@@ -0,0 +1,75 @@
+
+#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;
+}
diff --git a/_src/codegen/cgasm.h b/_src/codegen/cgasm.h
new file mode 100644 (file)
index 0000000..455a425
--- /dev/null
@@ -0,0 +1,31 @@
+
+#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
diff --git a/_src/codegen/cgblock.cpp b/_src/codegen/cgblock.cpp
new file mode 100644 (file)
index 0000000..f92bf46
--- /dev/null
@@ -0,0 +1,24 @@
+
+#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;
+               }
+       }
+}
diff --git a/_src/codegen/cgblock.h b/_src/codegen/cgblock.h
new file mode 100644 (file)
index 0000000..38357d0
--- /dev/null
@@ -0,0 +1,26 @@
+
+#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
diff --git a/_src/codegen/cgcode.cpp b/_src/codegen/cgcode.cpp
new file mode 100644 (file)
index 0000000..bcd377f
--- /dev/null
@@ -0,0 +1,525 @@
+
+#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);
+}
diff --git a/_src/codegen/cgcode.h b/_src/codegen/cgcode.h
new file mode 100644 (file)
index 0000000..3dcded0
--- /dev/null
@@ -0,0 +1,408 @@
+
+#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
diff --git a/_src/codegen/cgdebug.cpp b/_src/codegen/cgdebug.cpp
new file mode 100644 (file)
index 0000000..f430dcd
--- /dev/null
@@ -0,0 +1,247 @@
+
+#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;
+}
diff --git a/_src/codegen/cgdebug.h b/_src/codegen/cgdebug.h
new file mode 100644 (file)
index 0000000..a25baae
--- /dev/null
@@ -0,0 +1,20 @@
+
+#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
diff --git a/_src/codegen/cgfixfp_x86.cpp b/_src/codegen/cgfixfp_x86.cpp
new file mode 100644 (file)
index 0000000..2841926
--- /dev/null
@@ -0,0 +1,680 @@
+
+#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;
+}
diff --git a/_src/codegen/cgfixfp_x86.h b/_src/codegen/cgfixfp_x86.h
new file mode 100644 (file)
index 0000000..6de7a79
--- /dev/null
@@ -0,0 +1,6 @@
+
+#ifndef CGFIXFP_X86_H
+#define CGFIXFP_X86_H
+
+#endif
+
diff --git a/_src/codegen/cgflow.cpp b/_src/codegen/cgflow.cpp
new file mode 100644 (file)
index 0000000..7c59b1e
--- /dev/null
@@ -0,0 +1,257 @@
+
+#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];
+       }
+}
diff --git a/_src/codegen/cgflow.h b/_src/codegen/cgflow.h
new file mode 100644 (file)
index 0000000..85667a3
--- /dev/null
@@ -0,0 +1,22 @@
+
+#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
diff --git a/_src/codegen/cgframe.cpp b/_src/codegen/cgframe.cpp
new file mode 100644 (file)
index 0000000..d1b93fc
--- /dev/null
@@ -0,0 +1,622 @@
+
+#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;
+                               }
+                       }
+               }
+       }
+}
+
diff --git a/_src/codegen/cgframe.h b/_src/codegen/cgframe.h
new file mode 100644 (file)
index 0000000..507b068
--- /dev/null
@@ -0,0 +1,63 @@
+
+#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
diff --git a/_src/codegen/cgframe_ppc.cpp b/_src/codegen/cgframe_ppc.cpp
new file mode 100644 (file)
index 0000000..3af2f58
--- /dev/null
@@ -0,0 +1,733 @@
+
+#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 );
+       }
+}
diff --git a/_src/codegen/cgframe_ppc.h b/_src/codegen/cgframe_ppc.h
new file mode 100644 (file)
index 0000000..0bdc8f0
--- /dev/null
@@ -0,0 +1,60 @@
+
+#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
diff --git a/_src/codegen/cgframe_x86.cpp b/_src/codegen/cgframe_x86.cpp
new file mode 100644 (file)
index 0000000..20d9ff6
--- /dev/null
@@ -0,0 +1,983 @@
+
+#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" );
+}
diff --git a/_src/codegen/cgframe_x86.h b/_src/codegen/cgframe_x86.h
new file mode 100644 (file)
index 0000000..87584f1
--- /dev/null
@@ -0,0 +1,78 @@
+
+#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
diff --git a/_src/codegen/cgint64.cpp b/_src/codegen/cgint64.cpp
new file mode 100644 (file)
index 0000000..b3a78af
--- /dev/null
@@ -0,0 +1,266 @@
+
+#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;
+}
diff --git a/_src/codegen/cgint64.h b/_src/codegen/cgint64.h
new file mode 100644 (file)
index 0000000..3eb6a94
--- /dev/null
@@ -0,0 +1,9 @@
+
+#ifndef CGINT64_H
+#define CGINT64_H
+
+#include "cgframe.h"
+
+#endif
+
+
diff --git a/_src/codegen/cgintset.cpp b/_src/codegen/cgintset.cpp
new file mode 100644 (file)
index 0000000..6efc60c
--- /dev/null
@@ -0,0 +1,59 @@
+
+#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;
+}
diff --git a/_src/codegen/cgintset.h b/_src/codegen/cgintset.h
new file mode 100644 (file)
index 0000000..e60b1c0
--- /dev/null
@@ -0,0 +1,21 @@
+
+#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
diff --git a/_src/codegen/cgmodule.cpp b/_src/codegen/cgmodule.cpp
new file mode 100644 (file)
index 0000000..613ce76
--- /dev/null
@@ -0,0 +1,86 @@
+
+#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();
+}
diff --git a/_src/codegen/cgmodule.h b/_src/codegen/cgmodule.h
new file mode 100644 (file)
index 0000000..1ec9a48
--- /dev/null
@@ -0,0 +1,47 @@
+
+#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
diff --git a/_src/codegen/cgmodule_ppc.cpp b/_src/codegen/cgmodule_ppc.cpp
new file mode 100644 (file)
index 0000000..eda924c
--- /dev/null
@@ -0,0 +1,207 @@
+
+#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";
+       }
+}
diff --git a/_src/codegen/cgmodule_ppc.h b/_src/codegen/cgmodule_ppc.h
new file mode 100644 (file)
index 0000000..ec50528
--- /dev/null
@@ -0,0 +1,25 @@
+
+#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
diff --git a/_src/codegen/cgmodule_x86.cpp b/_src/codegen/cgmodule_x86.cpp
new file mode 100644 (file)
index 0000000..f611455
--- /dev/null
@@ -0,0 +1,301 @@
+
+#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(){
+}
diff --git a/_src/codegen/cgmodule_x86.h b/_src/codegen/cgmodule_x86.h
new file mode 100644 (file)
index 0000000..b970fbd
--- /dev/null
@@ -0,0 +1,26 @@
+
+#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
diff --git a/_src/codegen/cgstd.h b/_src/codegen/cgstd.h
new file mode 100644 (file)
index 0000000..40c424e
--- /dev/null
@@ -0,0 +1,2 @@
+
+#include "../compiler/stdutil.h"
diff --git a/_src/codegen/cgutil.cpp b/_src/codegen/cgutil.cpp
new file mode 100644 (file)
index 0000000..d05c693
--- /dev/null
@@ -0,0 +1,310 @@
+
+#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);
diff --git a/_src/codegen/cgutil.h b/_src/codegen/cgutil.h
new file mode 100644 (file)
index 0000000..0ec4150
--- /dev/null
@@ -0,0 +1,57 @@
+
+#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
diff --git a/_src/codegen/codegen.cpp b/_src/codegen/codegen.cpp
new file mode 100644 (file)
index 0000000..df23bf0
--- /dev/null
@@ -0,0 +1,77 @@
+
+#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();
+}
diff --git a/_src/codegen/codegen.h b/_src/codegen/codegen.h
new file mode 100644 (file)
index 0000000..fb37092
--- /dev/null
@@ -0,0 +1,10 @@
+
+#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
diff --git a/_src/compiler/bcc.cpp b/_src/compiler/bcc.cpp
new file mode 100644 (file)
index 0000000..af371b0
--- /dev/null
@@ -0,0 +1,62 @@
+
+#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;
+}
diff --git a/_src/compiler/block.cpp b/_src/compiler/block.cpp
new file mode 100644 (file)
index 0000000..d101a7e
--- /dev/null
@@ -0,0 +1,533 @@
+
+#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);
+}
diff --git a/_src/compiler/block.h b/_src/compiler/block.h
new file mode 100644 (file)
index 0000000..be16a26
--- /dev/null
@@ -0,0 +1,109 @@
+
+#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
diff --git a/_src/compiler/config.cpp b/_src/compiler/config.cpp
new file mode 100644 (file)
index 0000000..d3b326b
--- /dev/null
@@ -0,0 +1,138 @@
+
+#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
diff --git a/_src/compiler/config.h b/_src/compiler/config.h
new file mode 100644 (file)
index 0000000..02e3b23
--- /dev/null
@@ -0,0 +1,14 @@
+
+#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
diff --git a/_src/compiler/config.h.bak b/_src/compiler/config.h.bak
new file mode 100644 (file)
index 0000000..e5fdf77
--- /dev/null
@@ -0,0 +1,14 @@
+
+#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
diff --git a/_src/compiler/decl.cpp b/_src/compiler/decl.cpp
new file mode 100644 (file)
index 0000000..def12c3
--- /dev/null
@@ -0,0 +1,190 @@
+
+#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;
+}
diff --git a/_src/compiler/decl.h b/_src/compiler/decl.h
new file mode 100644 (file)
index 0000000..9e132de
--- /dev/null
@@ -0,0 +1,47 @@
+
+#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
diff --git a/_src/compiler/declseq.cpp b/_src/compiler/declseq.cpp
new file mode 100644 (file)
index 0000000..4def231
--- /dev/null
@@ -0,0 +1,19 @@
+
+#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;
+}
diff --git a/_src/compiler/declseq.h b/_src/compiler/declseq.h
new file mode 100644 (file)
index 0000000..99b2163
--- /dev/null
@@ -0,0 +1,21 @@
+
+#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
diff --git a/_src/compiler/exp.cpp b/_src/compiler/exp.cpp
new file mode 100644 (file)
index 0000000..40527da
--- /dev/null
@@ -0,0 +1,940 @@
+#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));
+}
diff --git a/_src/compiler/exp.h b/_src/compiler/exp.h
new file mode 100644 (file)
index 0000000..2b5169a
--- /dev/null
@@ -0,0 +1,229 @@
+
+#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
diff --git a/_src/compiler/make.bat b/_src/compiler/make.bat
new file mode 100644 (file)
index 0000000..d99c3cf
--- /dev/null
@@ -0,0 +1 @@
+bmk0 -a -r -z -o ~/blitzmax/bin/bcc bcc.cpp
diff --git a/_src/compiler/module.cpp b/_src/compiler/module.cpp
new file mode 100644 (file)
index 0000000..52b9c32
--- /dev/null
@@ -0,0 +1,3 @@
+
+#include "std.h"
+#include "module.h"
diff --git a/_src/compiler/module.h b/_src/compiler/module.h
new file mode 100644 (file)
index 0000000..acb9709
--- /dev/null
@@ -0,0 +1,5 @@
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#endif
diff --git a/_src/compiler/output.cpp b/_src/compiler/output.cpp
new file mode 100644 (file)
index 0000000..ad59e9b
--- /dev/null
@@ -0,0 +1,149 @@
+
+#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
diff --git a/_src/compiler/output.h b/_src/compiler/output.h
new file mode 100644 (file)
index 0000000..97b13a1
--- /dev/null
@@ -0,0 +1,14 @@
+
+#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
diff --git a/_src/compiler/parser.cpp b/_src/compiler/parser.cpp
new file mode 100644 (file)
index 0000000..7d15da6
--- /dev/null
@@ -0,0 +1,1861 @@
+
+#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();
+}
diff --git a/_src/compiler/parser.h b/_src/compiler/parser.h
new file mode 100644 (file)
index 0000000..790f73a
--- /dev/null
@@ -0,0 +1,135 @@
+
+#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
diff --git a/_src/compiler/scope.cpp b/_src/compiler/scope.cpp
new file mode 100644 (file)
index 0000000..5a2ff0b
--- /dev/null
@@ -0,0 +1,33 @@
+
+#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);
+}
diff --git a/_src/compiler/scope.h b/_src/compiler/scope.h
new file mode 100644 (file)
index 0000000..9218713
--- /dev/null
@@ -0,0 +1,15 @@
+
+#ifndef SCOPE_H
+#define SCOPE_H
+
+struct Val;
+
+struct Scope{
+       virtual         ~Scope();
+       
+       virtual Val*    find( string id );
+       
+       Val*                    findTypeIdent( string id );
+};
+
+#endif
diff --git a/_src/compiler/std.cpp b/_src/compiler/std.cpp
new file mode 100644 (file)
index 0000000..f9cc304
--- /dev/null
@@ -0,0 +1,234 @@
+
+#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;
+}
diff --git a/_src/compiler/std.h b/_src/compiler/std.h
new file mode 100644 (file)
index 0000000..73bcf0c
--- /dev/null
@@ -0,0 +1,51 @@
+
+#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
diff --git a/_src/compiler/stdutil.cpp b/_src/compiler/stdutil.cpp
new file mode 100644 (file)
index 0000000..2ab5758
--- /dev/null
@@ -0,0 +1,544 @@
+
+#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
diff --git a/_src/compiler/stdutil.h b/_src/compiler/stdutil.h
new file mode 100644 (file)
index 0000000..bd6aa49
--- /dev/null
@@ -0,0 +1,173 @@
+
+#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
diff --git a/_src/compiler/stm.cpp b/_src/compiler/stm.cpp
new file mode 100644 (file)
index 0000000..0837f2e
--- /dev/null
@@ -0,0 +1,807 @@
+
+#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) );
+}
diff --git a/_src/compiler/stm.h b/_src/compiler/stm.h
new file mode 100644 (file)
index 0000000..a86c62a
--- /dev/null
@@ -0,0 +1,327 @@
+
+#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
diff --git a/_src/compiler/toker.cpp b/_src/compiler/toker.cpp
new file mode 100644 (file)
index 0000000..3da61b6
--- /dev/null
@@ -0,0 +1,482 @@
+
+#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)+">";
+}
diff --git a/_src/compiler/toker.cpp.bak b/_src/compiler/toker.cpp.bak
new file mode 100644 (file)
index 0000000..9d17eef
--- /dev/null
@@ -0,0 +1,472 @@
+
+#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)+">";
+}
diff --git a/_src/compiler/toker.h b/_src/compiler/toker.h
new file mode 100644 (file)
index 0000000..41a4cc0
--- /dev/null
@@ -0,0 +1,119 @@
+
+#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
diff --git a/_src/compiler/type.cpp b/_src/compiler/type.cpp
new file mode 100644 (file)
index 0000000..74c9641
--- /dev/null
@@ -0,0 +1,693 @@
+
+#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);
+}
diff --git a/_src/compiler/type.h b/_src/compiler/type.h
new file mode 100644 (file)
index 0000000..46c4136
--- /dev/null
@@ -0,0 +1,313 @@
+
+#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
diff --git a/_src/compiler/val.cpp b/_src/compiler/val.cpp
new file mode 100644 (file)
index 0000000..c103789
--- /dev/null
@@ -0,0 +1,662 @@
+
+#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;
+}
diff --git a/_src/compiler/val.h b/_src/compiler/val.h
new file mode 100644 (file)
index 0000000..c3af93a
--- /dev/null
@@ -0,0 +1,55 @@
+
+#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