ソースを参照

Added compiler src.

blitz-research 11 年 前
コミット
ef5d0cfcaa
70 ファイル変更16434 行追加0 行削除
  1. 2 0
      _src/.gitignore
  2. 596 0
      _src/codegen/cgallocregs.cpp
  3. 9 0
      _src/codegen/cgallocregs.h
  4. 75 0
      _src/codegen/cgasm.cpp
  5. 31 0
      _src/codegen/cgasm.h
  6. 24 0
      _src/codegen/cgblock.cpp
  7. 26 0
      _src/codegen/cgblock.h
  8. 525 0
      _src/codegen/cgcode.cpp
  9. 408 0
      _src/codegen/cgcode.h
  10. 247 0
      _src/codegen/cgdebug.cpp
  11. 20 0
      _src/codegen/cgdebug.h
  12. 680 0
      _src/codegen/cgfixfp_x86.cpp
  13. 6 0
      _src/codegen/cgfixfp_x86.h
  14. 257 0
      _src/codegen/cgflow.cpp
  15. 22 0
      _src/codegen/cgflow.h
  16. 622 0
      _src/codegen/cgframe.cpp
  17. 63 0
      _src/codegen/cgframe.h
  18. 733 0
      _src/codegen/cgframe_ppc.cpp
  19. 60 0
      _src/codegen/cgframe_ppc.h
  20. 983 0
      _src/codegen/cgframe_x86.cpp
  21. 78 0
      _src/codegen/cgframe_x86.h
  22. 266 0
      _src/codegen/cgint64.cpp
  23. 9 0
      _src/codegen/cgint64.h
  24. 59 0
      _src/codegen/cgintset.cpp
  25. 21 0
      _src/codegen/cgintset.h
  26. 86 0
      _src/codegen/cgmodule.cpp
  27. 47 0
      _src/codegen/cgmodule.h
  28. 207 0
      _src/codegen/cgmodule_ppc.cpp
  29. 25 0
      _src/codegen/cgmodule_ppc.h
  30. 301 0
      _src/codegen/cgmodule_x86.cpp
  31. 26 0
      _src/codegen/cgmodule_x86.h
  32. 2 0
      _src/codegen/cgstd.h
  33. 310 0
      _src/codegen/cgutil.cpp
  34. 57 0
      _src/codegen/cgutil.h
  35. 77 0
      _src/codegen/codegen.cpp
  36. 10 0
      _src/codegen/codegen.h
  37. 62 0
      _src/compiler/bcc.cpp
  38. 533 0
      _src/compiler/block.cpp
  39. 109 0
      _src/compiler/block.h
  40. 138 0
      _src/compiler/config.cpp
  41. 14 0
      _src/compiler/config.h
  42. 14 0
      _src/compiler/config.h.bak
  43. 190 0
      _src/compiler/decl.cpp
  44. 47 0
      _src/compiler/decl.h
  45. 19 0
      _src/compiler/declseq.cpp
  46. 21 0
      _src/compiler/declseq.h
  47. 940 0
      _src/compiler/exp.cpp
  48. 229 0
      _src/compiler/exp.h
  49. 1 0
      _src/compiler/make.bat
  50. 3 0
      _src/compiler/module.cpp
  51. 5 0
      _src/compiler/module.h
  52. 149 0
      _src/compiler/output.cpp
  53. 14 0
      _src/compiler/output.h
  54. 1861 0
      _src/compiler/parser.cpp
  55. 135 0
      _src/compiler/parser.h
  56. 33 0
      _src/compiler/scope.cpp
  57. 15 0
      _src/compiler/scope.h
  58. 234 0
      _src/compiler/std.cpp
  59. 51 0
      _src/compiler/std.h
  60. 544 0
      _src/compiler/stdutil.cpp
  61. 173 0
      _src/compiler/stdutil.h
  62. 807 0
      _src/compiler/stm.cpp
  63. 327 0
      _src/compiler/stm.h
  64. 482 0
      _src/compiler/toker.cpp
  65. 472 0
      _src/compiler/toker.cpp.bak
  66. 119 0
      _src/compiler/toker.h
  67. 693 0
      _src/compiler/type.cpp
  68. 313 0
      _src/compiler/type.h
  69. 662 0
      _src/compiler/val.cpp
  70. 55 0
      _src/compiler/val.h

+ 2 - 0
_src/.gitignore

@@ -0,0 +1,2 @@
+/old/*
+/setup/*

+ 596 - 0
_src/codegen/cgallocregs.cpp

@@ -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
+}

+ 9 - 0
_src/codegen/cgallocregs.h

@@ -0,0 +1,9 @@
+
+#ifndef CGALLOCREGS_H
+#define CGALLOCREGS_H
+
+#include "cgframe.h"
+
+void cgAllocRegs( CGFrame *frame );
+
+#endif

+ 75 - 0
_src/codegen/cgasm.cpp

@@ -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;
+}

+ 31 - 0
_src/codegen/cgasm.h

@@ -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

+ 24 - 0
_src/codegen/cgblock.cpp

@@ -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;
+		}
+	}
+}

+ 26 - 0
_src/codegen/cgblock.h

@@ -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

+ 525 - 0
_src/codegen/cgcode.cpp

@@ -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);
+}

+ 408 - 0
_src/codegen/cgcode.h

@@ -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

+ 247 - 0
_src/codegen/cgdebug.cpp

@@ -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;
+}

+ 20 - 0
_src/codegen/cgdebug.h

@@ -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

+ 680 - 0
_src/codegen/cgfixfp_x86.cpp

@@ -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;
+}

+ 6 - 0
_src/codegen/cgfixfp_x86.h

@@ -0,0 +1,6 @@
+
+#ifndef CGFIXFP_X86_H
+#define CGFIXFP_X86_H
+
+#endif
+

+ 257 - 0
_src/codegen/cgflow.cpp

@@ -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];
+	}
+}

+ 22 - 0
_src/codegen/cgflow.h

@@ -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

+ 622 - 0
_src/codegen/cgframe.cpp

@@ -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;
+				}
+			}
+		}
+	}
+}
+

+ 63 - 0
_src/codegen/cgframe.h

@@ -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

+ 733 - 0
_src/codegen/cgframe_ppc.cpp

@@ -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 );
+	}
+}

+ 60 - 0
_src/codegen/cgframe_ppc.h

@@ -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

+ 983 - 0
_src/codegen/cgframe_x86.cpp

@@ -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" );
+}

+ 78 - 0
_src/codegen/cgframe_x86.h

@@ -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

+ 266 - 0
_src/codegen/cgint64.cpp

@@ -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;
+}

+ 9 - 0
_src/codegen/cgint64.h

@@ -0,0 +1,9 @@
+
+#ifndef CGINT64_H
+#define CGINT64_H
+
+#include "cgframe.h"
+
+#endif
+
+

+ 59 - 0
_src/codegen/cgintset.cpp

@@ -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;
+}

+ 21 - 0
_src/codegen/cgintset.h

@@ -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

+ 86 - 0
_src/codegen/cgmodule.cpp

@@ -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();
+}

+ 47 - 0
_src/codegen/cgmodule.h

@@ -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

+ 207 - 0
_src/codegen/cgmodule_ppc.cpp

@@ -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";
+	}
+}

+ 25 - 0
_src/codegen/cgmodule_ppc.h

@@ -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

+ 301 - 0
_src/codegen/cgmodule_x86.cpp

@@ -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(){
+}

+ 26 - 0
_src/codegen/cgmodule_x86.h

@@ -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

+ 2 - 0
_src/codegen/cgstd.h

@@ -0,0 +1,2 @@
+
+#include "../compiler/stdutil.h"

+ 310 - 0
_src/codegen/cgutil.cpp

@@ -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);

+ 57 - 0
_src/codegen/cgutil.h

@@ -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

+ 77 - 0
_src/codegen/codegen.cpp

@@ -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();
+}

+ 10 - 0
_src/codegen/codegen.h

@@ -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

+ 62 - 0
_src/compiler/bcc.cpp

@@ -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;
+}

+ 533 - 0
_src/compiler/block.cpp

@@ -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);
+}

+ 109 - 0
_src/compiler/block.h

@@ -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

+ 138 - 0
_src/compiler/config.cpp

@@ -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

+ 14 - 0
_src/compiler/config.h

@@ -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

+ 14 - 0
_src/compiler/config.h.bak

@@ -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

+ 190 - 0
_src/compiler/decl.cpp

@@ -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;
+}

+ 47 - 0
_src/compiler/decl.h

@@ -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

+ 19 - 0
_src/compiler/declseq.cpp

@@ -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;
+}

+ 21 - 0
_src/compiler/declseq.h

@@ -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

+ 940 - 0
_src/compiler/exp.cpp

@@ -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));
+}

+ 229 - 0
_src/compiler/exp.h

@@ -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

+ 1 - 0
_src/compiler/make.bat

@@ -0,0 +1 @@
+bmk0 -a -r -z -o ~/blitzmax/bin/bcc bcc.cpp

+ 3 - 0
_src/compiler/module.cpp

@@ -0,0 +1,3 @@
+
+#include "std.h"
+#include "module.h"

+ 5 - 0
_src/compiler/module.h

@@ -0,0 +1,5 @@
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#endif

+ 149 - 0
_src/compiler/output.cpp

@@ -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;
+}

+ 14 - 0
_src/compiler/output.h

@@ -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

+ 1861 - 0
_src/compiler/parser.cpp

@@ -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();
+}

+ 135 - 0
_src/compiler/parser.h

@@ -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

+ 33 - 0
_src/compiler/scope.cpp

@@ -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);
+}

+ 15 - 0
_src/compiler/scope.h

@@ -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

+ 234 - 0
_src/compiler/std.cpp

@@ -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;
+}

+ 51 - 0
_src/compiler/std.h

@@ -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

+ 544 - 0
_src/compiler/stdutil.cpp

@@ -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

+ 173 - 0
_src/compiler/stdutil.h

@@ -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

+ 807 - 0
_src/compiler/stm.cpp

@@ -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) );
+}

+ 327 - 0
_src/compiler/stm.h

@@ -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

+ 482 - 0
_src/compiler/toker.cpp

@@ -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)+">";
+}

+ 472 - 0
_src/compiler/toker.cpp.bak

@@ -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)+">";
+}

+ 119 - 0
_src/compiler/toker.h

@@ -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

+ 693 - 0
_src/compiler/type.cpp

@@ -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);
+}

+ 313 - 0
_src/compiler/type.h

@@ -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

+ 662 - 0
_src/compiler/val.cpp

@@ -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;
+}

+ 55 - 0
_src/compiler/val.h

@@ -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