blitz3d/compiler/stmtnode.cpp

587 lines
14 KiB
C++

#include "std.h"
#include "nodes.h"
static string fileLabel;
static map<string,string> fileMap;
void StmtNode::debug( int pos,Codegen *g ){
if( g->debug ){
TNode *t=fileLabel.size() ? global( fileLabel ) : iconst(0);
g->code( call( "__bbDebugStmt",iconst( pos ),t ) );
}
}
void StmtSeqNode::reset( const string &file,const string &lab ){
fileLabel="";
fileMap.clear();
fileMap[file]=lab;
}
////////////////////////
// Statement Sequence //
////////////////////////
void StmtSeqNode::semant( Environ *e ){
for( int k=0;k<stmts.size();++k ){
try{ stmts[k]->semant( e ); }
catch( Ex &x ){
if( x.pos<0 ) x.pos=stmts[k]->pos;
if( !x.file.size() ) x.file=file;
throw;
}
}
}
void StmtSeqNode::translate( Codegen *g ){
string t=fileLabel;
fileLabel=file.size() ? fileMap[file] : "";
for( int k=0;k<stmts.size();++k ){
StmtNode *stmt=stmts[k];
stmt->debug( stmts[k]->pos,g );
try{
stmt->translate( g );
}
catch( Ex &x ){
if( x.pos<0 ) x.pos=stmts[k]->pos;
if( !x.file.size() ) x.file=file;
throw;
}
}
fileLabel=t;
}
/////////////////
// An Include! //
/////////////////
void IncludeNode::semant( Environ *e ){
label=genLabel();
fileMap[file]=label;
stmts->semant( e );
}
void IncludeNode::translate( Codegen *g ){
if( g->debug ) g->s_data( file,label );
stmts->translate( g );
}
///////////////////
// a declaration //
///////////////////
void DeclStmtNode::semant( Environ *e ){
decl->proto( e->decls,e );
decl->semant( e );
}
void DeclStmtNode::translate( Codegen *g ){
decl->translate( g );
}
//////////////////////////////
// Dim AND declare an Array //
//////////////////////////////
void DimNode::semant( Environ *e ){
Type *t=tagType( tag,e );
if( Decl *d=e->findDecl( ident ) ){
ArrayType *a=d->type->arrayType();
if( !a || a->dims!=exprs->size() || (t && a->elementType!=t) ){
ex( "Duplicate identifier" );
}
sem_type=a;sem_decl=0;
}else{
if( e->level>0 ) ex( "Array not found in main program" );
if( !t ) t=Type::int_type;
sem_type=d_new ArrayType( t,exprs->size() );
sem_decl=e->decls->insertDecl( ident,sem_type,DECL_ARRAY );
e->types.push_back( sem_type );
}
exprs->semant( e );
exprs->castTo( Type::int_type,e );
}
void DimNode::translate( Codegen *g ){
TNode *t;
g->code( call( "__bbUndimArray",global( "_a"+ident ) ) );
for( int k=0;k<exprs->size();++k ){
t=add( global( "_a"+ident ),iconst( k*4+12 ) );
t=move( exprs->exprs[k]->translate(g),mem( t ) );
g->code( t );
}
g->code( call( "__bbDimArray",global( "_a"+ident ) ) );
if( !sem_decl ) return;
int et;
Type *ty=sem_type->arrayType()->elementType;
if( ty==Type::int_type ) et=1;
else if( ty==Type::float_type ) et=2;
else if( ty==Type::string_type ) et=3;
else et=5;
g->align_data( 4 );
g->i_data( 0,"_a"+ident );
g->i_data( et );
g->i_data( exprs->size() );
for( k=0;k<exprs->size();++k ) g->i_data( 0 );
}
////////////////
// Assignment //
////////////////
void AssNode::semant( Environ *e ){
var->semant( e );
if( var->sem_type->constType() ) ex( "Constants can not be assigned to" );
if( var->sem_type->vectorType() ) ex( "Blitz arrays can not be assigned to" );
expr=expr->semant( e );
expr=expr->castTo( var->sem_type,e );
}
void AssNode::translate( Codegen *g ){
g->code( var->store( g,expr->translate( g ) ) );
}
//////////////////////////
// Expression statement //
//////////////////////////
void ExprStmtNode::semant( Environ *e ){
expr=expr->semant( e );
}
void ExprStmtNode::translate( Codegen *g ){
TNode *t=expr->translate( g );
if( expr->sem_type==Type::string_type ) t=call( "__bbStrRelease",t );
g->code( t );
}
////////////////
// user label //
////////////////
void LabelNode::semant( Environ *e ){
if( Label *l=e->findLabel( ident ) ){
if( l->def>=0 ) ex( "duplicate label" );
l->def=pos;l->data_sz=data_sz;
}else e->insertLabel( ident,pos,-1,data_sz );
ident=e->funcLabel+ident;
}
void LabelNode::translate( Codegen *g ){
g->label( "_l"+ident );
}
//////////////////
// Restore data //
//////////////////
void RestoreNode::semant( Environ *e ){
if( e->level>0 ) e=e->globals;
if( ident.size()==0 ) sem_label=0;
else{
sem_label=e->findLabel( ident );
if( !sem_label ) sem_label=e->insertLabel( ident,-1,pos,-1 );
}
}
void RestoreNode::translate( Codegen *g ){
TNode *t=global( "__DATA" );
if( sem_label ) t=add( t,iconst( sem_label->data_sz*8 ) );
g->code( call( "__bbRestore",t ) );
}
////////////////////
// Goto statement //
////////////////////
void GotoNode::semant( Environ *e ){
if( !e->findLabel( ident ) ){
e->insertLabel( ident,-1,pos,-1 );
}
ident=e->funcLabel+ident;
}
void GotoNode::translate( Codegen *g ){
g->code( jump( "_l"+ident ) );
}
/////////////////////
// Gosub statement //
/////////////////////
void GosubNode::semant( Environ *e ){
if( e->level>0 ) ex( "'Gosub' may not be used inside a function" );
if( !e->findLabel( ident ) ) e->insertLabel( ident,-1,pos,-1 );
ident=e->funcLabel+ident;
}
void GosubNode::translate( Codegen *g ){
g->code( jsr( "_l"+ident ) );
}
//////////////////
// If statement //
//////////////////
void IfNode::semant( Environ *e ){
expr=expr->semant( e );
expr=expr->castTo( Type::int_type,e );
stmts->semant( e );
if( elseOpt ) elseOpt->semant( e );
}
void IfNode::translate( Codegen *g ){
if( ConstNode *c=expr->constNode() ){
if( c->intValue() ) stmts->translate( g );
else if( elseOpt ) elseOpt->translate( g );
}else{
string _else=genLabel();
g->code( jumpf( expr->translate( g ),_else ) );
stmts->translate( g );
if( elseOpt ){
string _else2=genLabel();
g->code( jump( _else2 ) );
g->label( _else );
elseOpt->translate( g );
_else=_else2;
}
g->label( _else );
}
}
///////////
// Break //
///////////
void ExitNode::semant( Environ *e ){
sem_brk=e->breakLabel;
if( !sem_brk.size() ) ex( "break must appear inside a loop" );
}
void ExitNode::translate( Codegen *g ){
g->code( d_new TNode( IR_JUMP,0,0,sem_brk ) );
}
/////////////////////
// While statement //
/////////////////////
void WhileNode::semant( Environ *e ){
expr=expr->semant( e );
expr=expr->castTo( Type::int_type,e );
string brk=e->setBreak( sem_brk=genLabel() );
stmts->semant( e );
e->setBreak( brk );
}
void WhileNode::translate( Codegen *g ){
string loop=genLabel();
if( ConstNode *c=expr->constNode() ){
if( !c->intValue() ) return;
g->label( loop );
stmts->translate( g );
g->code( jump( loop ) );
}else{
string cond=genLabel();
g->code( jump( cond ) );
g->label( loop );
stmts->translate( g );
debug( wendPos,g );
g->label( cond );
g->code( jumpt( expr->translate( g ),loop ) );
}
g->label( sem_brk );
}
///////////////////
// For/Next loop //
///////////////////
ForNode::ForNode( VarNode *var,ExprNode *from,ExprNode *to,ExprNode *step,StmtSeqNode *ss,int np )
:var(var),fromExpr(from),toExpr(to),stepExpr(step),stmts(ss),nextPos(np){
}
ForNode::~ForNode(){
delete stmts;
delete stepExpr;
delete toExpr;
delete fromExpr;
delete var;
}
void ForNode::semant( Environ *e ){
var->semant( e );
Type *ty=var->sem_type;
if( ty->constType() ) ex( "Index variable can not be constant" );
if( ty!=Type::int_type && ty!=Type::float_type ){
ex( "index variable must be integer or real" );
}
fromExpr=fromExpr->semant( e );
fromExpr=fromExpr->castTo( ty,e );
toExpr=toExpr->semant( e );
toExpr=toExpr->castTo( ty,e );
stepExpr=stepExpr->semant( e );
stepExpr=stepExpr->castTo( ty,e );
if( !stepExpr->constNode() ) ex( "Step value must be constant" );
string brk=e->setBreak( sem_brk=genLabel() );
stmts->semant( e );
e->setBreak( brk );
}
void ForNode::translate( Codegen *g ){
TNode *t;Type *ty=var->sem_type;
//initial assignment
g->code( var->store( g,fromExpr->translate( g ) ) );
string cond=genLabel();
string loop=genLabel();
g->code( jump( cond ) );
g->label( loop );
stmts->translate( g );
//execute the step part
debug( nextPos,g );
int op=ty==Type::int_type ? IR_ADD : IR_FADD;
t=d_new TNode( op,var->load( g ),stepExpr->translate( g ) );
g->code( var->store( g,t ) );
//test for loop cond
g->label( cond );
op=stepExpr->constNode()->floatValue()>0 ? '>' : '<';
t=compare( op,var->load( g ),toExpr->translate( g ),ty );
g->code( jumpf( t,loop ) );
g->label( sem_brk );
}
///////////////////////////////
// For each object of a type //
///////////////////////////////
void ForEachNode::semant( Environ *e ){
var->semant( e );
Type *ty=var->sem_type;
if( ty->structType()==0 ) ex( "Index variable is not a NewType" );
Type *t=e->findType( typeIdent );
if( !t ) ex( "Type name not found" );
if( t!=ty ) ex( "Type mismatch" );
string brk=e->setBreak( sem_brk=genLabel() );
stmts->semant( e );
e->setBreak( brk );
}
void ForEachNode::translate( Codegen *g ){
TNode *t,*l,*r;
string _loop=genLabel();
string objFirst,objNext;
if( var->isObjParam() ){
objFirst="__bbObjEachFirst2";
objNext="__bbObjEachNext2";
}else{
objFirst="__bbObjEachFirst";
objNext="__bbObjEachNext";
}
l=var->translate( g );
r=global( "_t"+typeIdent );
t=jumpf( call( objFirst,l,r ),sem_brk );
g->code( t );
g->label( _loop );
stmts->translate( g );
debug( nextPos,g );
t=jumpt( call( objNext,var->translate( g ) ),_loop );
g->code( t );
g->label( sem_brk );
}
////////////////////////////
// Return from a function //
////////////////////////////
void ReturnNode::semant( Environ *e ){
if( e->level<=0 && expr ){
ex( "Main program cannot return a value" );
}
if( e->level>0 ){
if( !expr ){
if( e->returnType==Type::float_type ){
expr=d_new FloatConstNode( 0 );
}else if( e->returnType==Type::string_type ){
expr=d_new StringConstNode( "" );
}else if( e->returnType->structType() ){
expr=d_new NullNode();
}else{
expr=d_new IntConstNode( 0 );
}
}
expr=expr->semant( e );
expr=expr->castTo( e->returnType,e );
returnLabel=e->funcLabel+"_leave";
}
}
void ReturnNode::translate( Codegen *g ){
if( !expr ){
g->code( d_new TNode( IR_RET,0,0 ) );
return;
}
TNode *t=expr->translate( g );
if( expr->sem_type==Type::float_type ){
g->code( d_new TNode( IR_FRETURN,t,0,returnLabel ) );
}else{
g->code( d_new TNode( IR_RETURN,t,0,returnLabel ) );
}
}
//////////////////////
// Delete statement //
//////////////////////
void DeleteNode::semant( Environ *e ){
expr=expr->semant( e );
if( expr->sem_type->structType()==0 ) ex( "Can't delete non-Newtype" );
}
void DeleteNode::translate( Codegen *g ){
TNode *t=expr->translate( g );
g->code( call( "__bbObjDelete",t ) );
}
///////////////////////////
// Delete each of a type //
///////////////////////////
void DeleteEachNode::semant( Environ *e ){
Type *t=e->findType( typeIdent );
if( !t || t->structType()==0 ) ex( "Specified name is not a NewType name" );
}
void DeleteEachNode::translate( Codegen *g ){
g->code( call( "__bbObjDeleteEach",global( "_t"+typeIdent ) ) );
}
///////////////////////////
// Insert object in list //
///////////////////////////
void InsertNode::semant( Environ *e ){
expr1=expr1->semant( e );
expr2=expr2->semant( e );
StructType *t1=expr1->sem_type->structType();
StructType *t2=expr2->sem_type->structType();
if( !t1 || !t2 ) ex( "Illegal expression type" );
if( t1!=t2 ) ex( "Objects types are differnt" );
}
void InsertNode::translate( Codegen *g ){
TNode *t1=expr1->translate( g );
if( g->debug ) t1=jumpf( t1,"__bbNullObjEx" );
TNode *t2=expr2->translate( g );
if( g->debug ) t2=jumpf( t2,"__bbNullObjEx" );
string s=before ? "__bbObjInsBefore" : "__bbObjInsAfter";
g->code( call( s,t1,t2 ) );
}
////////////////////////
// A select statement //
////////////////////////
void SelectNode::semant( Environ *e ){
expr=expr->semant( e );
Type *ty=expr->sem_type;
if( ty->structType() ) ex( "Select cannot be used with objects" );
//we need a temp var
Decl *d=e->decls->insertDecl( genLabel(),expr->sem_type,DECL_LOCAL );
sem_temp=d_new DeclVarNode( d );
for( int k=0;k<cases.size();++k ){
CaseNode *c=cases[k];
c->exprs->semant( e );
c->exprs->castTo( ty,e );
c->stmts->semant( e );
}
if( defStmts ) defStmts->semant( e );
}
void SelectNode::translate( Codegen *g ){
Type *ty=expr->sem_type;
g->code( sem_temp->store( g,expr->translate( g ) ) );
vector<string> labs;
string brk=genLabel();
for( int k=0;k<cases.size();++k ){
CaseNode *c=cases[k];
labs.push_back( genLabel() );
for( int j=0;j<c->exprs->size();++j ){
ExprNode *e=c->exprs->exprs[j];
TNode *t=compare( '=',sem_temp->load( g ),e->translate( g ),ty );
g->code( jumpt( t,labs.back() ) );
}
}
if( defStmts ) defStmts->translate( g );
g->code( jump( brk ) );
for( k=0;k<cases.size();++k ){
CaseNode *c=cases[k];
g->label( labs[k] );
c->stmts->translate( g );
g->code( jump( brk ) );
}
g->label( brk );
}
////////////////////////////
// Repeat...Until/Forever //
////////////////////////////
void RepeatNode::semant( Environ *e ){
sem_brk=genLabel();
string brk=e->setBreak( sem_brk );
stmts->semant( e );
e->setBreak( brk );
if( expr ){
expr=expr->semant( e );
expr=expr->castTo( Type::int_type,e );
}
}
void RepeatNode::translate( Codegen *g ){
string loop=genLabel();
g->label( loop );
stmts->translate( g );
debug( untilPos,g );
if( ConstNode *c=expr ? expr->constNode() : 0 ){
if( !c->intValue() ) g->code( jump( loop ) );
}else{
if( expr ) g->code( jumpf( expr->translate( g ),loop ) );
else g->code( jump( loop ) );
}
g->label( sem_brk );
}
///////////////
// Read data //
///////////////
void ReadNode::semant( Environ *e ){
var->semant( e );
if( var->sem_type->constType() ) ex( "Constants can not be modified" );
if( var->sem_type->structType() ) ex( "Data can not be read into an object" );
}
void ReadNode::translate( Codegen *g ){
TNode *t;
if( var->sem_type==Type::int_type ) t=call( "__bbReadInt" );
else if( var->sem_type==Type::float_type ) t=fcall( "__bbReadFloat" );
else t=call( "__bbReadStr" );
g->code( var->store( g,t ) );
}