// $Id: Bcons.java,v 1.11 2000/09/27 04:42:00 msato Exp $
// $RWC_Release: Omni-1.6 $
// $RWC_Copyright:
//  Omni Compiler Software Version 1.5-1.6
//  Copyright (C) 2002 PC Cluster Consortium
//  
//  This software is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License version
//  2.1 published by the Free Software Foundation.
//  
//  Omni Compiler Software Version 1.0-1.4
//  Copyright (C) 1999, 2000, 2001.
//   Tsukuba Research Center, Real World Computing Partnership, Japan.
//  
//  Please check the Copyright and License information in the files named
//  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
//  Software release kit.
//  
//  
//  $
package exc.block;
import exc.object.*;

//
// static class Block constructor
//
public class Bcons {
  public static Block Statement(Xobject x){
    return new SimpleBlock(Xcode.LIST,BasicBlock.Statement(x));
  }

  public static Block Cond(Xobject x){
    return new SimpleBlock(Xcode.LIST,BasicBlock.Cond(x));
  }

  public static Block BasicBlock(BasicBlock bb){
    return new SimpleBlock(Xcode.LIST,bb);
  }

  public static Block emptyBlock(){
    return new SimpleBlock(Xcode.LIST,new BasicBlock());
  }

  public static BlockList emptyBody(){
    return new BlockList();
  }

  public static BlockList emptyBody(Xobject id_list, Xobject decls){
    return new BlockList(id_list,decls);
  }

  public static Block COMPOUND(BlockList b_list){
    return new CompoundBlock(b_list);
  }

  public static Block PRAGMA(int code, int pragma, Xobject args,
			     BlockList body){
    return new PragmaBlock(code,pragma,args,body);
  }

  public static Block IF(BasicBlock cond,BlockList then_part,
			 BlockList else_part){
    /* to fix, the problem of two-body IF */
    if(then_part != null && then_part.getIdentList() != null)
      then_part = new BlockList(Bcons.COMPOUND(then_part));
    if(else_part != null && else_part.getIdentList() != null)
      else_part = new BlockList(Bcons.COMPOUND(else_part));
    return new IfBlock(cond,then_part,else_part);
  }

  public static Block IF(Xobject cond,Block then_part,Block else_part){
    return new IfBlock(BasicBlock.Cond(cond),
		       new BlockList(then_part),new BlockList(else_part));
  }

  public static Block FOR(BasicBlock init,BasicBlock cond,BasicBlock iter,
			  BlockList body){
    return new ForBlock(init,cond,iter,body);
  }

  public static Block FOR(Xobject init,Xobject cond,Xobject iter,
			  Block body){
    return new ForBlock(BasicBlock.Statement(init),
			BasicBlock.Cond(cond),
			BasicBlock.Statement(iter),
			new BlockList(body));
  }

  public static Block WHILE(BasicBlock cond,BlockList body){
    return new CondBlock(Xcode.WHILE_STATEMENT,cond,body);
  }

  public static Block WHILE(Xobject cond,Block body){
    return new CondBlock(Xcode.WHILE_STATEMENT,
			 BasicBlock.Cond(cond),new BlockList(body));
  }

  public static Block DO(BlockList body,BasicBlock cond){
    return new CondBlock(Xcode.DO_STATEMENT,cond,body);
  }

  public static Block DO(Block body,Xobject cond){
    return new CondBlock(Xcode.DO_STATEMENT,
			 BasicBlock.Cond(cond),new BlockList(body));
  }

  public static Block SWITCH(BasicBlock cond,BlockList body){
    return new CondBlock(Xcode.SWITCH_STATEMENT,cond,body);
  }

  public static Block SWITCH(Xobject cond,Block body){
    return new CondBlock(Xcode.SWITCH_STATEMENT,
			 BasicBlock.Cond(cond),new BlockList(body));
  }

  public static Block BREAK(){
    return new SimpleBlock(Xcode.BREAK_STATEMENT);
  }

  public static Block CONTINUE(){
    return new SimpleBlock(Xcode.CONTINUE_STATEMENT);
  }

  public static Block GOTO(Xobject label){
    return new LabelBlock(Xcode.GOTO_STATEMENT,label);
  }

  public static Block LABEL(Xobject label){
    return new LabelBlock(Xcode.STATEMENT_LABEL,label);
  }

  public static Block CASE(Xobject label){
    return new LabelBlock(Xcode.CASE_LABEL,label);
  }

  public static Block DEFAULT_LABEL(){
    return new SimpleBlock(Xcode.DEFAULT_LABEL);
  }

  public static Block RETURN(){
    return new SimpleBlock(Xcode.RETURN_STATEMENT);
  }

  public static Block RETURN(BasicBlock ret){
    return new SimpleBlock(Xcode.RETURN_STATEMENT,ret);
  }

  public static Block RETURN(Xobject ret){
    return new SimpleBlock(Xcode.RETURN_STATEMENT,BasicBlock.Cond(ret));
  }

  //
  // build routine from XobjectDef and Xobject
  //
  public static FunctionBlock buildFunctionBlock(XobjectDef d){
    return new FunctionBlock(d.getName(),d.getFuncParamIdList(),
			     d.getFuncParamDecls(),
			     buildBlock(d.getFuncBody()),
			     d.getFile());
  }
    
  static BlockList buildList(Xobject v){
    Block b;
    BlockList b_list = new BlockList();
    if(v == null) return b_list;
    switch(v.Opcode()){
    case Xcode.LIST:	/* (LIST statement ....) */
      break;
    case Xcode.COMPOUND_STATEMENT:
      /* (COMPOUND_STATEMENT id-list decl statement-list) */
      b_list.id_list = v.getArg(0);
      b_list.decls = v.getArg(1);
      v = v.getArg(2);
      break;
    default:
      /* BlockList, which has one statement */
      b = buildBlock(v);
      b.setLineNo(v.getLineNo());
      b_list.add(b);
      return b_list;
    }
    addBlocks(v,b_list);
    return b_list;
  }
    
  static void addBlocks(Xobject v, BlockList b_list){
    Block b;
    if(v == null) return;
    switch(v.Opcode()){
    case Xcode.LIST:
      for(XobjArgs a = v.getArgs(); a != null; a = a.nextArgs()){
	addBlocks(a.getArg(),b_list);	// call recursively
      }
      break;
    case Xcode.EXPR_STATEMENT: 	/* just statement */
      b = b_list.getTail();
      if(b == null || b.Opcode() != Xcode.LIST){
	b = new SimpleBlock(Xcode.LIST);
	b.setLineNo(v.getLineNo());
	b_list.add(b);
      }
      Statement s = new Statement(v.getArg(0));
      s.setLineNo(v.getLineNo());
      b.getBasicBlock().add(s);
      break;
    default:
      b = buildBlock(v);
      b.setLineNo(v.getLineNo());
      b_list.add(b);
    }
  }

  public static Block buildBlock(Xobject v){
    switch(v.Opcode()){
    default:
      fatal("build: unknown code");
      return null;

    case Xcode.LIST:	/* (LIST statement ....) */
      fatal("LIST is appear in non-compound statement");
      return null;

    case Xcode.COMPOUND_STATEMENT:
      return COMPOUND(buildList(v));

    case Xcode.OMP_PRAGMA:
      return PRAGMA(Xcode.OMP_PRAGMA,v.getArg(0).getInt(),v.getArg(1),
		    buildList(v.getArg(2)));

    case Xcode.TEA_PRAGMA:
      return PRAGMA(Xcode.TEA_PRAGMA,v.getArg(0).getInt(),v.getArg(1),
		    buildList(v.getArg(2)));

    case Xcode.IF_STATEMENT: /* (IF_STATMENT cond then-part else-part) */
      return IF(BasicBlock.Cond(v.getArg(0)),
		buildList(v.getArg(1)),buildList(v.getArg(2)));

    case Xcode.FOR_STATEMENT:  /* (FOR init cond iter body) */
      return FOR(BasicBlock.Statement(v.getArg(0)),
		 BasicBlock.Cond(v.getArg(1)),
		 BasicBlock.Statement(v.getArg(2)),
		 buildList(v.getArg(3)));

    case Xcode.WHILE_STATEMENT: /* (WHILE_STATEMENT cond body) */
      return WHILE(BasicBlock.Cond(v.getArg(0)),buildList(v.getArg(1)));

    case Xcode.DO_STATEMENT: /* (DO_STATEMENT body cond) */
      return DO(buildList(v.getArg(0)),BasicBlock.Cond(v.getArg(1)));

    case Xcode.SWITCH_STATEMENT: /* (SWITCH_STATEMENT value body) */
      return SWITCH(BasicBlock.Cond(v.getArg(0)),
		    buildList(v.getArg(1)));

    case Xcode.BREAK_STATEMENT:  /* (BREAK_STATEMENT) */
      return BREAK();

    case Xcode.CONTINUE_STATEMENT: /* (CONTINUE_STATEMENT) */
      return CONTINUE();

    case Xcode.GOTO_STATEMENT:	/* (GOTO_STATEMENT label) */
      return GOTO(v.getArg(0));

    case Xcode.STATEMENT_LABEL: /* (STATEMENT_LABEL label_ident) */
      return LABEL(v.getArg(0));

    case Xcode.CASE_LABEL: 		/* (CASE_LABEL value) */
      return CASE(v.getArg(0));

    case Xcode.DEFAULT_LABEL: /* (DEFAULT_LABEL) */
      return DEFAULT_LABEL();

    case Xcode.RETURN_STATEMENT: /* (RETURN_STATEMENT value) */
      return RETURN(BasicBlock.Cond(v.getArg(0)));

    case Xcode.EXPR_STATEMENT:
      /* signle statement Basic Block */
      return new SimpleBlock(Xcode.LIST,BasicBlock.Statement(v.getArg(0)));
    }
  }

  static void fatal(String msg){
    System.err.println("Fatal Bcons:"+msg);
    Thread.dumpStack();
    System.exit(1);
  }
}
