// $Id: BlockList.java,v 1.11 2003/03/26 18:54:21 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.*;

public class BlockList {
  Block head,tail;
  Block parent;

  Xobject id_list;
  Xobject decls;

  // construct empty BlockList
  public BlockList(){
  }

  // construct empty BlockList
  public BlockList(Block b){
    if(b != null) add(b);
  }

  // construct empty for COMPOUND_STATEMENT
  public BlockList(Xobject id_list, Xobject decls){
    this.id_list = id_list;
    this.decls = decls;
  }

  public BlockList(BlockList b_l){
    if(b_l.id_list != null) id_list = b_l.id_list.copy();
    if(b_l.decls != null) decls = b_l.decls.copy();
    for(Block b = b_l.getHead(); b != null; b = b.getNext())
      this.add(b.copy());
  }

  public BlockList copy(){ return new BlockList(this); }

  public Block getTail() { return tail; }
  public Block getHead() { return head; }
  public Block getParent() { return parent; }
  public BlockList getParentList() 
  { return parent == null? null : parent.getParent(); }
  public void setParent(Block b) { parent = b; }

  // add block at tail
  public void add(Block b){
    if(head == null){
      head = tail = b;
    } else {
      tail.next = b;
      b.prev = tail;
      tail = b;
    }
    b.parent = this;
  }
  public void add(BasicBlock bb){
    add(new SimpleBlock(Xcode.LIST,bb));
  }
  public void add(Xobject x){
    add(new SimpleBlock(Xcode.LIST,BasicBlock.Statement(x)));
  }

  // insert block before head
  public void insert(Block b){
    if(head == null){
      head = tail = b;
    } else {
      head.prev = b;
      b.next = head;
      head = b;
    }
    b.parent = this;
  }
  public void insert(BasicBlock bb){
    insert(new SimpleBlock(Xcode.LIST,bb));
  }
  public void insert(Xobject x){
    insert(new SimpleBlock(Xcode.LIST,BasicBlock.Statement(x)));
  }

  public boolean isEmpty(){
    return head == null;
  }
  public boolean isSingle(){
    return head != null && head == tail;
  }

  public Xobject getIdentList() { return id_list; }
  public Xobject getDecls() { return decls; }
    
  public Ident findLocalIdent(Ident id){
    if(id_list == null) return null;
    for(XobjArgs a = id_list.getArgs(); a != null; a = a.nextArgs())
      if(a.getArg() == (Xobject)id) return id;
    return null;
  }

  public Ident findLocalIdent(String s){
    if(id_list == null) return null;
    for(XobjArgs a = id_list.getArgs(); a != null; a = a.nextArgs())
      if(s.equals(((Ident)a.getArg()).getName()))
	return (Ident)a.getArg();
    return null;
  }

  public void addIdent(Ident id){
    if(id_list == null) id_list = Xcons.emptyIdList();
    id_list.add((Xobject) id);
  }

  public void removeDeclInit(){
    Ident id;
    XobjArgs a;

    if(decls == null) return;
    for(a = decls.getArgs(); a != null; a = a.nextArgs()){
      Xobject d = a.getArg();
      if(d.Opcode() != Xcode.VAR_DECL) continue;
      if(d.getArg(1) != null) break;
    }
    if(a == null) return;
    BasicBlock bb = new BasicBlock();
    for(a = decls.getArgs(); a != null; a = a.nextArgs()){
      Xobject d = a.getArg();
      if(d.Opcode() != Xcode.VAR_DECL) continue;
      if(d.getArg(1) == null) continue;
      if((id = findLocalIdent(d.getArg(0).getName())) == null)
	fatal("removeDeclInit: no ID");
      if(id.getStorageClass() == StorageClass.STATIC) continue;
      if(id.Type().isConst()) continue;

      XobjArgs init = d.getArgs().nextArgs();
      if(init.getArg().Opcode() == Xcode.LIST ||
	 init.getArg().Opcode() == Xcode.STRING_CONSTANT)
	expandInitializer(bb,id.Ref(),init);
      else
	bb.add(Xcons.Set(id.Ref(),init.getArg()));

      d.setArg(1,null);  // remove!
    }
    insert(bb);
  }

  void expandInitializer(BasicBlock bb, Xobject x, XobjArgs init){
    Xobject v;
    if(init == null) return;
    Xtype type = x.Type();
    switch(type.getKind()){
    case Xtype.BASIC:
    case Xtype.ENUM:
    case Xtype.FUNCTION:
    case Xtype.POINTER:
      v = init.getArg();
      if(v.Opcode() == Xcode.LIST) fatal("expandInit: bad scalar init");
      bb.add(Xcons.Set(x,v));
      break;
    case Xtype.STRUCT:
      v = init.getArg();
      if(v.Opcode() == Xcode.LIST) init = v.getArgs();
      XobjArgs mlist = type.getMemberList().getArgs();
      for( ; init != null; init = init.nextArgs()){
	Ident mid = (Ident)mlist.getArg();
	Xobject addr = Xcons.memberAddr(Xcons.AddrOf(x),mid.getName());
	expandInitializer(bb,Xcons.PointerRef(addr),init);
	mlist = mlist.nextArgs();
      } 
      break;
    case Xtype.ARRAY:
      v = init.getArg();
      if(v.Opcode() == Xcode.STRING_CONSTANT){
	Xobject f = 
	  Xcons.Symbol(Xcode.FUNC_ADDR,
		       Xtype.Pointer(Xtype.Function(Xtype.voidType)),
		       "strcpy");
	bb.add(Xcons.functionCall(f,Xcons.List(x,v)));
	break;
      }
      if(v.Opcode() == Xcode.LIST) init = v.getArgs();
      int i = 0;
      for( ; init != null; init = init.nextArgs()){
	Xobject addr = Xcons.binaryOp(Xcode.PLUS_EXPR,x,
				      Xcons.IntConstant(i++));
	expandInitializer(bb,Xcons.PointerRef(addr),init);
      }
      break;
    case Xtype.UNION:
      fatal("cannot expand initializer for UNION");
    default:
      fatal("expandInitializer: unknown type");
    }
  }

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

  public Xobject toXobject(){
    Xobject v;
    if(head == null) return null;
    if(head == tail && head.Opcode() != Xcode.LIST)
      v = head.toXobject();
    else {
      v = new XobjList(Xcode.LIST);
      for(Block b = head; b != null; b = b.getNext()){
	if(b.Opcode() == Xcode.LIST){
	  for(Statement s = b.getBasicBlock().getHead();
	      s != null; s = s.getNext()){
	    Xobject x = new XobjList(Xcode.EXPR_STATEMENT,
				     s.getExpr());
	    x.setLineNo(s.getLineNo());
	    v.add(x);
	  }
	} else
	  v.add(b.toXobject());
      }
    }
    if(id_list == null && decls == null) return v;
    else return new XobjList(Xcode.COMPOUND_STATEMENT,id_list,decls,v);
  }
}





