%{
#include "global.h"
#include "symbol.c"

extern char * yytext;
short copy_stage = 0;
char * copy_string;
char out_str [65536];
char aux_string [1024];
%}

//Deficiencies:

//Statements of the form a = b are not handled properly.
// if a variable is undeclared,we get unexpected results.

//----------------------------------------------------------------
//	parse.y 
//----------------------------------------------------------------

%token MODULE 
%token ENDMODULE
%token IF
%token ELSE
%token INPUT
%token OUTPUT
%token INOUT
%token REG
%token WIRE
%token ASSIGN
%token INITIAL
%token ALWAYS
%token BEG
%token END
%token EQUALS
%token ID
%token SEPARATOR
%token DONE
%token INTEGER
%token NUM
%token BITSTRING
%token EVENT_OR
%token POSEDGE,NEGEDGE
%token REAL,CASE, DEFAULT, ENDCASE, SEMICOLON, COLON, LPAREN, RPAREN, LSQ, RSQ, HASH, AT,COMMA, EQUALS, TICK,AND,OR,NOT,PLUS,MINUS
%token COMPARE,GTEQ,GT,LTEQ,LT

%union 
{
	struct
	{
		struct id_node * outputid;
		struct id_node * caseid;
		struct id_node * id;
	} node;
	
	struct 
	{
		int start; 
		int end;
	} vector;
	int value;
	float rvalue;
}
%%

start			:
				{
					sym_init();
				}
				module_name port_list module_items ENDMODULE
				{
					//cleanup();
					fprintf(stdout,"\nendmodule\n");
					fprintf(stderr,"Done.Exiting .. \n");
					exit(0);
				}
				;
module_name		: MODULE
				{
					fprintf(stdout,
							"`include \"gen_lib.h\"\n\n"); 
					fprintf(stdout,"%s ",yytext);	
				}
				ID
				{ fprintf(stdout,"%s ",yytext); }
				;
port_list		: LPAREN
				{ fprintf(stdout,"(");}
					 id_list RPAREN SEMICOLON 
				{ fprintf(stdout,");\n\n");}
					port_decls
				| LPAREN RPAREN SEMICOLON
				{ fprintf(stdout,"();\n\n");}		
				| SEMICOLON
				{ fprintf(stdout,"%s\n\n",yytext); }
				;
id_list			: ID COMMA 
					{fprintf(stdout,"%s,",$1.node.id->id_name);}
				  id_list	
				| ID
					{fprintf(stdout,"%s",$1.node.id->id_name);}
				;
vid_list		: vid COMMA 
				{ if(copy_stage) strcat(copy_string,", ");} 
					vid_list
				| vid
				;
vid 			: LSQ NUM COLON NUM RSQ ID
				{
					struct id_node * id = (struct id_node *)
						malloc(sizeof(struct id_node));
					id->id_name = $6.node.id->id_name;
					id->start = $2.value;
					id->end = $4.value;
					id->next = NULL;
					insert(id, id->id_name);

					if(copy_stage)
					{	 
						strcat(copy_string,"[");
						//aux_string = (char *)malloc(10);	
						sprintf(aux_string,"%d",$2.value);
						strcat(copy_string,aux_string);
						strcat(copy_string,":"); 
						sprintf(aux_string,"%d",$4.value);
						strcat(copy_string,aux_string);
						strcat(copy_string,"]"); 
						//free(aux_string);
						strcat(copy_string,$6.node.id->id_name);	
					}
				}
				| ID
				{
					struct id_node * id = (struct id_node *)
						malloc(sizeof(struct id_node));
					id->id_name = $1.node.id->id_name;
					id->start = -1;
					id->end = -1;
					id->next = NULL;
					insert(id, id->id_name);
			
					if(copy_stage)
						strcat(copy_string,$1.node.id->id_name);
				}
				;
port_decls  	: INPUT vid_list SEMICOLON port_decls
				| OUTPUT vid_list SEMICOLON port_decls
			  	| INPUT vid_list SEMICOLON
				| OUTPUT vid_list SEMICOLON
				;
delay			: HASH NUM
				{	
					if(copy_stage)
					{
						strcat(copy_string,"#");
						//aux_string = (char *)malloc(10);	
						sprintf(aux_string,"%d",$2.value);
						strcat(copy_string,aux_string);
						//free(aux_string);	
						strcat(copy_string," ");
					}
					else
						fprintf(stderr,"\nTiming construct ignored\n\n");
				}
				|
				;
event			: delay
				| AT LPAREN event_list RPAREN
				;
event_list		: edge ID EVENT_OR event_list
				| edge ID
				;
edge			: POSEDGE
				| NEGEDGE
				|
				;
vector			: LSQ NUM COLON NUM RSQ
				{
					$$.vector.start=$2.value;
					$$.vector.end=$4.value;
					
					if(copy_stage)
					{	 
						strcat(copy_string,"["); 
						//aux_string = (char *)malloc(10);	
						sprintf(aux_string,"%d",$2.value);
						strcat(copy_string,aux_string);
						strcat(copy_string,":"); 
						sprintf(aux_string,"%d",$4.value);
						strcat(copy_string,aux_string);
						strcat(copy_string,"]"); 
						//free(aux_string);
					}
				}
				| 
				{
					$$.vector.start=-1;
					$$.vector.end=-1;
				}
				;
subscript		: LSQ ID RSQ
				{
					if(copy_stage)
					{
						strcat(copy_string,"[");	
						strcat(copy_string,$2.node.id->id_name);	
						strcat(copy_string,"]");
					}
				}	
				| LSQ NUM RSQ
				{
					if(copy_stage)
					{
						strcat(copy_string,"[");
						//aux_string = (char *)malloc(10);	
						sprintf(aux_string,"%d",$2.value);
						strcat(copy_string,aux_string);
						//free(aux_string);	
						strcat(copy_string,"]");
					}
				}	
				| vector
				; 
module_items	: module_item module_items
				|
				;
module_item		: cont_assigns
				| always_block
				| initial_block
				| var_decls
				;
cont_assigns	: ASSIGN delay assign_stmts SEMICOLON
				;
always_block	: ALWAYS event block
				;
initial_block	: INITIAL
				{
					copy_stage = 1;
					copy_string = (char *) malloc (10000);
					copy_string[0] = '\0';
					strcat(copy_string,"initial\n");
					fprintf (stderr, "Warning:non-synthesizable initial construct\n");
				}
				delay block
				{
					fprintf(stdout,"%s",copy_string);
					free(copy_string);
					copy_stage = 0;
				} 
				;
var_decls		: type vid_list SEMICOLON
				{
					strcat(copy_string,";\n");
					fprintf(stdout,"%s\n",copy_string);
					free(copy_string);	
					copy_stage = 0;
				}
				;
type			: INTEGER
				{	 
					copy_stage = 1;
					copy_string = (char *)malloc (10000);
					copy_string[0] = '\0';
					strcat(copy_string,"integer ");
				}
				| REG 
				{	 
					copy_stage = 1;
					copy_string = (char *)malloc (10000);
					copy_string[0] = '\0';
					strcat(copy_string,"reg ");
				}
				| WIRE 
				{	 
					copy_stage = 1;
					copy_string = (char *)malloc (10000);
					copy_string[0] = '\0';
					strcat(copy_string,"wire ");
				}
				| REAL
				{	 
					copy_stage = 1;
					copy_string = (char *)malloc (10000);
					copy_string[0] = '\0';
					strcat(copy_string,"real ");
					fprintf(stderr,"non-synthesisable construct:real variable\n");
				}
				;
assign_stmts	: assignment COMMA assign_stmts
				| assignment
				;
assignment		: ID
				{ if(copy_stage) strcat(copy_string,$1.node.id->id_name);} 
					subscript EQUALS 
				{ if(copy_stage) strcat(copy_string," = ");} 
					expression
				{
					struct id_node * id = (struct id_node *)
							malloc(sizeof(struct id_node)); 
					struct id_node * id1 = (struct id_node *) 
						lookup ($1.node.id->id_name);
					if(!copy_stage)
					{
						if(id1)
							id1 = dup_list(id1);
						else
						{
							id1 = (struct id_node *)
									malloc(sizeof(struct id_node));
							id1->id_name = (char *)malloc(strlen(yytext) + 1);
							id1->next = NULL;
							id1->start = -1;
							id1->end = -1;
							strcpy(id1->id_name, yytext);
						}
						id = optimise($6.node.id,OR,id1);
						$$.node.id = id1;
						$$.node.id->next = id;
					}	
				}
				;
case_assign		: ID subscript EQUALS expression
				{
					struct id_node * id = (struct id_node *)
							malloc(sizeof(struct id_node)); 
					struct id_node * id1 = (struct id_node *) 
						lookup ($1.node.id->id_name);
					if(id1)
						id1 = dup_list(id1);
					else
					{
						id1 = (struct id_node *)
								malloc(sizeof(struct id_node));
						id1->id_name = (char *)malloc(strlen(yytext) + 1);
						id1->next = NULL;
						id1->start = -1;
						id1->end = -1;
						strcpy(id1->id_name, yytext);
					}
					
					id = optimise($4.node.id,OR,NULL);
					$$.node.id = id1;
					$$.node.id->next = id;
				}
				|
				;
block			: BEG 
				{ if(copy_stage) strcat(copy_string,"begin\n");}
					statements END
				{ if(copy_stage) strcat(copy_string,"end\n");}
				| if_or_case
				| assignment SEMICOLON
				{ if(copy_stage) strcat(copy_string,";\n");}
				;
statements		: delay assignment SEMICOLON 
				{ if(copy_stage) strcat(copy_string,";\n");}
					statements
				| if_or_case statements
				|
				;
if_or_case		: IF LPAREN	condition RPAREN block 
				{
					get_latch($5.node.id->next,$5.node.id,$3.node.id);	
				}	
				| IF LPAREN condition RPAREN block ELSE block
				{
					if(strcmp($5.node.id->id_name,$7.node.id->id_name))
					{
						struct id_node * temp_id = get_next_temp(NULL,NULL);
						get_latch($5.node.id->next,$5.node.id,$3.node.id);	
						sprintf(out_str + strlen (out_str),"INRB %s(%s,%s);\n",
								get_next_inst(), $3.node.id->id_name,
								temp_id->id_name);
						get_latch($7.node.id->next,$7.node.id,temp_id);	
					}
					else
					{
						get_2to1_mux($5.node.id->next,$7.node.id->next,$5.node.id,$3.node.id);
					}
				}
				| CASE LPAREN condition RPAREN alternatives ENDCASE
				{
					convert_case($5.node.outputid,$5.node.id,$5.node.caseid,$3.node.id);
				}	
				;
alternatives	: alt COLON case_assign SEMICOLON alternatives
				{
					$3.node.id->next->next = $5.node.outputid;
					$$.node.outputid = $3.node.id->next;
					$3.node.id->next = $5.node.id;
					$$.node.id = $3.node.id;
					
					$1.node.id->next = $5.node.caseid;
					$$.node.caseid = $1.node.id;
				}
				| alt COLON case_assign SEMICOLON
				{
					$$.node.id = $3.node.id;
					$$.node.outputid = $3.node.id->next;
					$$.node.id->next = NULL;
					$$.node.outputid->next = NULL;
					
					$$.node.caseid = $1.node.id;
					$$.node.caseid->next = NULL;
				}
				;
alt				: BITSTRING
				{
					//printf("%s\n",$1.node.caseid);
					$$.node.id->id_name = $1.node.id->id_name;
					$$.node.id->next = NULL;
				}	
				| DEFAULT
				{
					$$.node.id->id_name = NULL;
					$$.node.id->next = NULL;
				}
				;
condition		:/* ID
				{
					struct id_node * id1 = (struct id_node *) 
						lookup ($1.node.id->id_name);
					if(id1)
						id1 = dup_list(id1);
					else
					{
						id1 = (struct id_node *)
								malloc(sizeof(struct id_node));
						id1->id_name = (char *)malloc(strlen(yytext) + 1);
						id1->next = NULL;
						strcpy(id1->id_name, yytext);
					}
					
					$$.node.id = id1;
				}
				|*/ expression
				{
					$$.node.id = $1.node.id;
				}
				;
expression		: e COMPARE 
				{ if(copy_stage) strcat(copy_string," == ");}
					e 
				{
					if(!copy_stage)	
						$$.node.id = get_comp(COMPARE,$1.node.id,$4.node.id);
				}
				| e GTEQ 
				{ if(copy_stage) strcat(copy_string," >= ");}
					e
				{
					if(!copy_stage)	
						$$.node.id = get_comp(GTEQ,$1.node.id,$4.node.id);
				}
				| e LTEQ 
				{ if(copy_stage) strcat(copy_string," <= ");}
					e
				{
					if(!copy_stage)	
						$$.node.id = get_comp(LTEQ,$1.node.id,$4.node.id);
				}
				| e LT 
				{ if(copy_stage) strcat(copy_string," < ");}
					e
				{
					if(!copy_stage)	
						$$.node.id = get_comp(LT,$1.node.id,$4.node.id);
				}
				| e GT 
				{ if(copy_stage) strcat(copy_string," > ");}
					e
				{
					if(!copy_stage)	
						$$.node.id = get_comp(GT,$1.node.id,$4.node.id);
				}
				| e
				{
					if(!copy_stage)
						$$.node.id = $1.node.id;
				}
				;
e				:e OR
				{ if(copy_stage) strcat(copy_string," | ");}
					t
				{
					struct id_node * id = (struct id_node *)
							malloc(sizeof(struct id_node));
					if(!copy_stage)
					{ 
						id = optimise($4.node.id,AND,NULL);
						id->next = $1.node.id;
						$$.node.id = id;
					}
				}
				| t
				{
					if(!copy_stage)
						$$.node.id = optimise($1.node.id,AND,NULL);
				}
				;
t				: t AND 
				{ if(copy_stage) strcat(copy_string," & ");}
					n
				{
					struct id_node * temp ;
					if(!copy_stage)
					{ 
						temp = get_not_gate($4.node.id);
						if(temp)
						{
							temp->next = $1.node.id;
							$$.node.id = temp;
						}
						else
						{	
							$4.node.id->next = $1.node.id;
							$$.node.id = $4.node.id;
						}
					}
				}
				| n
				{ 
					struct id_node * temp ;
					if(!copy_stage)
					{
						temp = get_not_gate($1.node.id);
						if(temp)
							$$.node.id = temp;
						else	
							$$.node.id = $1.node.id;
					}
				}
				;
n				: NOT 
				{ if(copy_stage) strcat(copy_string," ! ");}
					n
				{
					if(!copy_stage)
					{
						$$.node.id = $3.node.id;
						$$.node.id->num_nots_seen = 
									1 - $$.node.id->num_nots_seen;
					}
				}
				| plusop 
				{
					if(!copy_stage)
					{
						$1.node.id = reverse($1.node.id);
						$$.node.id = optimise($1.node.id,PLUS,NULL);
						$$.node.id->num_nots_seen = 0;
					}
				}
				;	
plusop			: plusop PLUS 
				{ if(copy_stage) strcat(copy_string," + ");}
					f
				{
					if(!copy_stage)
					{
						$4.node.id->next = $1.node.id;
						$$.node.id = $4.node.id;
						$$.node.id->opcode = PLUSOP;
					}
				}	
				| plusop MINUS  
				{ if(copy_stage) strcat(copy_string," - ");}
					f
				{
					if(!copy_stage)
					{
						$4.node.id->next = $1.node.id;
						$$.node.id = $4.node.id;
						$$.node.id->opcode = MINUSOP;
					}
				}	
				| f
				{
					if(!copy_stage)
					{
						$$.node.id = $1.node.id;
						$$.node.id->opcode = NOOP;
					}
				}
				;
f				: LPAREN 
				{ if(copy_stage) strcat(copy_string," ( ");}
					e RPAREN
				{
					if(!copy_stage)
						$$.node.id = optimise($3.node.id,OR,NULL);
					if(copy_stage) strcat(copy_string," ) ");
				}
				| ID
				{
					struct id_node * id1 = (struct id_node *) 
						lookup ($1.node.id->id_name);
					if(!copy_stage)
					{
						if(id1)
							id1 = dup_list(id1);
						else
						{
							id1 = (struct id_node *)
									malloc(sizeof(struct id_node));
							id1->id_name = (char *)malloc(strlen(yytext) + 1);
							id1->next = NULL;
							id1->start = -1;
							id1->end = -1;
							strcpy(id1->id_name, yytext);
						}
						
						$$.node.id = id1;
					}
					
					if(copy_stage) strcat(copy_string,$1.node.id->id_name);
				}
				| BITSTRING
				{
					if(!copy_stage)
						$$.node.id = $1.node.id;
					if(copy_stage) strcat(copy_string,$1.node.id->id_name);
				}
				| NUM
				{	
					if(copy_stage)
					{
						//aux_string = (char *)malloc(10);	
						sprintf(aux_string,"%d",$1.value);
						strcat(copy_string,aux_string);
						//free(aux_string);
					}
				}
				;
%%

int yyerror()
{
return 0;
}

struct id_node * get_not_gate(struct id_node * node)
{
	struct id_node * temp = get_next_temp(NULL,NULL);	
	if(node->num_nots_seen)
	{
		sprintf (out_str + strlen (out_str),"INRB %s(%s, %s);\n",get_next_inst(),
					node->id_name,temp->id_name); 
		strcpy(node->id_name,temp->id_name);
	}
	return node;
}  

struct id_node * get_comp(int type,struct id_node * id1,struct id_node * id2)
{
	struct id_node * temp_list = NULL;	
	struct id_node * temp = NULL;
	int i;
	int min_width = find_min_width(id1,id2); 

	switch(type)
	{
		case COMPARE:
			for(i = 0;i < min_width;i++)
			{	
				temp = get_next_temp(NULL,NULL);
				temp->next = temp_list;
				temp->start = -1;	
				temp->end = -1;	
				temp_list = temp;
				
				sprintf(out_str + strlen (out_str),"XOR2 %s(%s[%d], %s[%d], %s);\n",get_next_inst(),
							id1->id_name,(id1->start < id1->end) ? 
							id1->start + i : (id1->start - i),
							id2->id_name,(id2->start < id2->end) ? 
							id2->start + i : (id2->start - i),
							temp->id_name);
			}
			if((id1->start - id1->end + 1) > min_width)
			{
				for(i = min_width;i < abs(id1->start - id1->end) + 1;i++)
				{
					temp = get_next_temp(NULL,NULL);
					sprintf(out_str + strlen (out_str),"INRB %s(%s[%d], %s);\n",get_next_inst(),
							id1->id_name,(id1->start < id1->end)?
							id1->start + i:(id1->start - i),temp->id_name);
					temp->next = temp_list;
					temp->start = -1;	
					temp->end = -1;	
					temp_list = temp;
				}
			}
			else if((id2->start - id2->end + 1) > min_width)
			{
				for(i = min_width;i < abs(id2->start - id2->end) + 1;i++)
				{
					temp = get_next_temp(NULL,NULL);
					sprintf(out_str + strlen (out_str),"INRB %s(%s[%d], %s);\n",get_next_inst(),
							id2->id_name,(id2->start < id2->end)?
							id2->start + i:(id2->start - i),temp->id_name);
					temp->next = temp_list;
					temp->start = -1;	
					temp->end = -1;	
					temp_list = temp;
				}
			}
			temp = optimise(temp_list,AND,NULL);
			break;
		case GTEQ:
			temp = get_ckt(id1,id2);
			break;
		case LTEQ:
		//LTEQ is being passed the params in the reverse order
			temp = get_ckt(id2,id1);
			break;
		case GT:
		//GT is merely LTEQ inverted	
			temp = get_ckt(id2,id1);
			sprintf(out_str + strlen (out_str),"NOT %s(%s, ",get_next_inst(),
						temp->id_name);
			temp = get_next_temp(NULL,NULL);
			sprintf(out_str + strlen (out_str),"%s);\n",temp->id_name);
			break;
		case LT:
		//LT is merely GTEQ inverted	
			temp = get_ckt(id1,id2);
			sprintf(out_str + strlen (out_str),"NOT %s(%s, ",get_next_inst(),
						temp->id_name);
			temp = get_next_temp(NULL,NULL);
			sprintf(out_str + strlen (out_str),"%s);\n",temp->id_name);
			break;
		default:
			fprintf(stderr,"Invalid Argument passed to get_comp()\n");
			break;
	}	
	return temp;
}				

struct id_node * get_ckt(struct id_node * id1,struct id_node * id2)
{
	struct id_node * prev = NULL;
	struct id_node * temp_list = NULL;
	struct id_node * temp = NULL;
	struct id_node * new_temp = NULL;
	int i;
	char * name = (char *) malloc(25);
	int min_width = find_min_width(id1,id2);

	if(abs(id1->start - id1->end) + 1 > min_width)
	{
		for(i = 0;i < abs(id1->start - id1->end ) - min_width + 1;i++)
		{
			sprintf(name,"%s[%d]",id1->id_name,id1->start < id1->end ? 
					i + min_width + id1->start : (id1->end + min_width + i));
			temp = get_id_node(name);
			temp->next = temp_list;
			temp_list = temp;
		}
		temp = optimise(temp_list,OR,NULL);
	}
	else if(abs(id2->start - id2->end) + 1 > min_width)
	{
		for(i = 0;i < abs(id2->start - id2->end ) - min_width + 1;i++)
		{
			sprintf(name,"%s[%d]",id2->id_name,id2->start < id2->end ? 
					i + min_width + id2->start :( id2->end + min_width + i));
			temp = get_id_node(name);
			temp->next = temp_list;
			temp_list = temp;
		}
		temp = optimise(temp_list,OR,NULL);
		sprintf(out_str + strlen (out_str),"INRB %s(%s, ",get_next_inst(),temp->id_name);
		temp = get_next_temp(NULL,NULL);
		sprintf(out_str + strlen (out_str),"%s);\n",temp->id_name);
	}
	temp_list = NULL;

	sprintf(out_str + strlen (out_str), "%d\n",min_width);
	for(i = 0;i < min_width;i++)
	{
		//new_temp holds the value of the new temporaries created here
		//dont use temp here coz it holds some other useful value
		//see above
		
		new_temp = get_next_temp(NULL,NULL);
		sprintf(out_str + strlen (out_str),"INRB %s(%s[%d], %s);\n",get_next_inst(),id2->id_name,
					(id2->start < id2->end) ?
					id2->start + i:(id2->end + min_width - 1 - i),new_temp->id_name);
		sprintf(out_str + strlen (out_str)"\n");
		sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d], %s, ",get_next_inst(),id1->id_name,
					(id1->start < id1->end) ?
					id1->start + i:(id1->end + min_width - 1 - i),new_temp->id_name);
		new_temp = get_next_temp(NULL,NULL);
		sprintf(out_str + strlen (out_str),"%s);\n",new_temp->id_name);
		if(prev)
		{
			sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, ",get_next_inst(),prev->id_name,
							new_temp->id_name);
			new_temp = get_next_temp(NULL,NULL);
			sprintf(out_str + strlen (out_str),"%s);\n",new_temp->id_name);
		}
		
		new_temp->next = temp_list;
		temp_list = new_temp;
			
		if(prev)
		{
			new_temp = get_next_temp(NULL,NULL);
			sprintf(out_str + strlen (out_str), "\n");
			sprintf(out_str + strlen (out_str),"XOR2 %s(%s[%d], %s[%d], %s);\n",get_next_inst(),
					id2->id_name,
					(id2->start < id2->end) ?
					id2->start + i:(id2->end + min_width - 1 - i),
					id1->id_name,
					(id1->start < id1->end) ?
					id1->start + i:(id1->end + min_width - 1 - i),
					new_temp->id_name);
			sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, ",get_next_inst(),prev->id_name,
							new_temp->id_name);
			new_temp = get_next_temp(NULL,NULL);
			sprintf(out_str + strlen (out_str),"%s);\n",new_temp->id_name);
			prev = new_temp;
		}			
		else
		{
			new_temp = get_next_temp(NULL,NULL);
			sprintf(out_str + strlen (out_str),"XOR2 %s(%s[%d], %s[%d], %s);\n",get_next_inst(),
					id2->id_name,
					(id2->start < id2->end) ?
					id2->start + i:(id2->end + min_width - 1 - i),
					id1->id_name,
					(id1->start < id1->end) ?
					id1->start + i:(id1->end + min_width - 1 - i),
					new_temp->id_name);
			prev = new_temp;
		}
	}
	if(prev)
	{
		prev->next = temp_list;
		temp_list = prev;
	}
	temp = optimise(temp_list,OR,NULL);
	return temp;	
}
	
struct id_node * optimise(struct id_node * list,
				int which_gate,struct id_node * dest)
{
	struct id_node * new_list = list;
	struct id_node * list_head = list;
	
	struct id_node * first;
	struct id_node * second;
	struct id_node * temp;
	
	int min_width,i;
	assert(list);
	if(list_head->next == NULL)
	{
		min_width = find_min_width(list,dest);
		if(dest)
		{
			for(i = 0;i < min_width;i++)
				sprintf(out_str + strlen (out_str),"BUF %s(%s[%d],%s[%d]);\n",get_next_inst(),
							list->id_name,(list->start < list->end)?
							list->end - min_width + 1 + i:(list->end + min_width -1-i),
							dest->id_name,(dest->start < dest->end)?
							dest->end + min_width + 1 + i:
										(dest->end + min_width -1-i));
		}
	}
	while(1)
	{
		first = list_head;
		second = first->next;
		if(second == NULL)
			break;
		
		min_width = find_min_width(list,dest);
		if(second)
		{
			new_list = get_next_temp(first,second);
			
			if(! (first->start == -1 && second->start == -1 &&
						first->end == -1 && second->end == -1))
			{ 
				new_list->start = 0;
				new_list->end = min_width ;
			}
			else
			{
				new_list->start = -1;
				new_list->end = -1;
			}
				
				switch(which_gate)
				{
					case AND:
						if(! (first->start == -1 && second->start == -1 &&
									first->end == -1 && second->end == -1)) 
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d],%s[%d],%s[%d]);\n",
									get_next_inst(),
									first->id_name,(first->start < first->end)?
											first->start + i:(first->start - i),
									second->id_name,(second->start < second->end)?
										second->start + i:(second->start - i),
									(second->next||!dest)?
									new_list->id_name:dest->id_name,
									(second->next||!dest)? 
											(new_list->start < new_list->end ?
									new_list->start + i:(new_list->start - i)):
									(dest->start < dest->end ?
									dest->start + i:(dest -> end + i)));
						else
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",
									get_next_inst(),
									first->id_name,
									second->id_name,
									(second->next||!dest)?
									new_list->id_name:dest->id_name);
							break;
						
					case OR:
						if(! (first->start == -1 && second->start == -1 &&
									first->end == -1 && second->end == -1)) 
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"OR2 %s(%s[%d],%s[%d],%s[%d]);\n",
									get_next_inst(),
									first->id_name,(first->start < first->end)?
											first->start + i:(first->start - i),
									second->id_name,(second->start < second->end)?
											second->start + i:(second->start - i),
									(second->next||!dest)?
									new_list->id_name:dest->id_name,
									(second->next||!dest)? 
											(new_list->start < new_list->end ?
									new_list->start + i:(new_list->start - i)):
									(dest->start < dest->end ?
									dest->start + i:(dest -> end + i)));
						else
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"OR2 %s(%s, %s, %s);\n",
									get_next_inst(),
									first->id_name,
									second->id_name,
									(second->next||!dest)?
									new_list->id_name:dest->id_name);
						break;
					case PLUS:
						temp = (second->next||!dest) ? new_list:dest;
						get_adder(first,second,temp);
						break;
				}
			list_head = new_list;
			first = second->next;
		}
		else 
			first = NULL;
	
		while(first != NULL)
		{
			second = first->next;
			if(second)
			{
				temp = get_next_temp(first,second);
				temp->start = -1;
				temp->end = -1;
				
				switch(which_gate)
				{
					case AND:
						if(! (first->start == -1 && second->start == -1 &&
									first->end == -1 && second->end == -1)) 
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d],%s[%d],%s[%d]);\n",
									get_next_inst(),
									first->id_name,(first->start < first->end)?
										first->start + i:(first->start - i),
									second->id_name,(second->start < second->end)?
											second->start + i:(second->start - i),
									temp->id_name,(temp->start < temp->end)?
											temp->start + i:(temp->end + i));
						else
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",
									get_next_inst(),
									first->id_name,
									second->id_name,
									temp->id_name);
							
						break;
						
					case OR:
						if(! (first->start == -1 && second->start == -1 &&
									first->end == -1 && second->end == -1)) 
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"OR2 %s(%s[%d],%s[%d],%s[%d]);\n",
									get_next_inst(),
									first->id_name,(first->start < first->end)?
										first->start + i:(first->start - i),
									second->id_name,(second->start < second->end)?
											second->start + i:(second->start - i),
									temp->id_name,(temp->start < temp->end)?
											temp->start + i:(temp->end + i));
						else	
							for(i = 0;i < min_width;i++)
								sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",
									get_next_inst(),
									first->id_name,
									second->id_name,
									temp->id_name);
						break;
					case PLUS:
						get_adder(first,second,temp);
						break;			
				}
				
				new_list->next = temp;
				new_list = temp;
				
				first = second->next;
			}
			else	
			{	
				new_list->next = first;
				new_list = first;
				
				first = NULL;
			}
		}
	}
	list_head->next = NULL;
	return list_head;
}

void declare_ids (struct id_node * id, int mode)
	// 0 to remember, 1 to spit out everything
{
	struct id_node * ids[1024];
	static int cnt = 0;

	if (!mode)
		ids[cnt++] = id;
	else
	{
		int i;
		for (i = 0; i < cnt; i++)
			sprintf(out_str + strlen (out_str), "wire %s[%d:%d];\n", ids[i]->id_name, ids[i]->start, ids[i]->end);
		cnt = 0;
	}
}
		
	

void get_adder(struct id_node * first,struct id_node * second,
							struct id_node * res)
{
	struct id_node * not_output = NULL;
	struct id_node * list_node = NULL;
	int i;
	struct id_node * cin = NULL;

	switch(second->opcode)
	{
		case PLUSOP:
					if(! res)
					{			
						res = get_next_temp(NULL,NULL);	
						res->end = 0;
						res->start = abs(first->start - first->end) + 1;
					}		
					for(i = 0;i < abs(first->start - first->end) + 1;i++)
					{
						list_node = get_full_adder(first,second,res,cin,i);
						cin = list_node;	
					}
					if(abs(res->start - res->end ) >= abs(first->start - first->end)+1)
						sprintf(out_str + strlen (out_str),"BUF %s(%s,%s[%d]);\n",get_next_inst(),
							cin->id_name,res->id_name,(res->start < res->end)? 
									res->end - i:(res->end + i));
						
				break;	
		case MINUSOP:
				not_output = get_next_temp(NULL,NULL);
				sprintf(out_str + strlen (out_str),"INRB %s(%s, %s);\n",get_next_inst(),
								second->id_name,
								not_output->id_name);
				sprintf(out_str + strlen (out_str),"XOR2 %s(%s, %s, %s);\n",get_next_inst(),
								first->id_name,
								not_output->id_name,res->id_name);
				break;	
		default:break;
	}
}

struct id_node * get_full_adder(struct id_node * id1,struct id_node * id2,
				struct id_node * res,struct id_node * cin,int i)
{
	struct id_node * inter = get_next_temp(NULL,NULL);
	struct id_node * inter1 = get_next_temp(NULL,NULL);	
	struct id_node * inter2 = get_next_temp(NULL,NULL);	
	struct id_node * inter3 = get_next_temp(NULL,NULL);	
	struct id_node * cout = get_next_temp(NULL,NULL);	
	struct id_node * or_out = get_next_temp(NULL,NULL);	
	
	inter->start = 0;
	inter->end = abs(id1->start - id1->end);	
	inter1->start = 0;
	inter1->end = abs(id1->start - id1->end);	
	inter2->start = 0;
	inter2->end = abs(id1->start - id1->end);	
	inter3->start = 0;
	inter3->end = abs(id1->start - id1->end);	
	or_out->start = 0;
	or_out->end = abs(id1->start - id1->end);	
	
	if(cin)
	{
		sprintf(out_str + strlen (out_str),"XOR2 %s(%s[%d],%s,%s[%d]);\n",get_next_inst(),
						id1->id_name,(id1->start < id1->end)?
						id1->end - i:(id1->end + i),cin->id_name,
						inter->id_name,
						(inter->start < inter->end)?	
						inter->end - i : (inter->end + i));
		sprintf(out_str + strlen (out_str),"XOR2 %s(%s[%d],%s[%d],%s[%d]);\n",get_next_inst(),
						id2->id_name,(id2->start < id2->end)?
						id2->end - i:(id2->end + i),inter->id_name,
						(inter->start < inter->end)?
						inter->end - i:(inter->end + i),
						res->id_name,
						(res->start < res->end)?	
						res->end - i : (res->end + i));
		sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d],%s,%s[%d]);\n",get_next_inst(),
						id1->id_name,(id1->start < id1->end)?
						id1->end - i:(id1->end + i),cin->id_name,
						inter1->id_name,
						(inter1->start < inter1->end)?	
						inter1->end - i : (inter1->end + i));
		sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d],%s,%s[%d]);\n",get_next_inst(),
						id2->id_name,(id2->start < id2->end)?
						id2->end - i:(id2->end + i),cin->id_name,
						inter2->id_name,
						(inter2->start < inter2->end)?	
						inter2->end - i : (inter2->end + i));
		sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d],%s[%d],%s[%d]);\n",get_next_inst(),
						id2->id_name,(id2->start < id2->end)?
						id2->end - i:(id2->end + i),id1->id_name,
						(id1->start < id1->end)?
						id1->end - i:(id1->end + i),
						inter3->id_name,
						(inter3->start < inter3->end)?	
						inter3->end - i : (inter3->end + i));
		sprintf(out_str + strlen (out_str),"OR2 %s(%s[%d],%s[%d],%s[%d]);\n",get_next_inst(),
						inter1->id_name,(inter1->start < inter1->end)?
						inter1->end - i:(inter1->end + i),inter2->id_name,
						(inter2->start < inter2->end)?
						inter2->end - i:(inter2->end + i),
						or_out->id_name,
						(or_out->start < or_out->end)?	
						or_out->end - i : (or_out->end + i));
		sprintf(out_str + strlen (out_str),"OR2 %s(%s[%d],%s[%d],%s);\n",get_next_inst(),
						inter3->id_name,(inter3->start < inter3->end)?
						inter3->end - i:(inter3->end + i),or_out->id_name,
						(or_out->start < or_out->end)?
						or_out->end - i:(or_out->end + i),
						cout->id_name);
	}
	else
	{		
		sprintf(out_str + strlen (out_str),"XOR2 %s(%s[%d],%s[%d],%s[%d]);\n",get_next_inst(),
						id1->id_name,(id1->start < id1->end)?
						id1->end - i:(id1->end + i),id2->id_name,
						(id2->start < id2->end)?
						id2->end - i:(id2->end + i),
						res->id_name,
						(res->start < res->end)?	
						res->end - i : (res->end + i));
		sprintf(out_str + strlen (out_str),"AND2 %s(%s[%d],%s[%d],%s);\n",get_next_inst(),
						id2->id_name,(id2->start < id2->end)?
						id2->end - i:(id2->end + i),id1->id_name,
						(id1->start < id1->end)?
						id1->end - i:(id1->end + i),
						cout->id_name);
	}	
	return cout;		
}

struct id_node * get_next_temp(struct id_node * first,
					struct id_node * second)
{
	static int temp = 0;
	struct id_node * id = (struct id_node * )
			malloc (sizeof(struct id_node));
	char * temp_str = ( char *) malloc (15*sizeof(char));
	sprintf ( temp_str,"__TEMP_%d",temp++);
	id->id_name = temp_str;
	id->start = -1;
	id->end = -1;
	if(first)
	{
		id->start = first->start;
		id->end = first->end;
	}
	id->next = NULL;
	return id;
}

char * get_next_inst()
{
	static int gatenum = 0;
	char * temp_str = (char *) malloc (15 * sizeof(char));
	sprintf ( temp_str,"__GATE_%d",gatenum++);
	return temp_str;
}

void get_latch(struct id_node * d_inp,
			struct id_node * q,struct id_node * clk)
{
	sprintf(out_str + strlen (out_str),"FDIS1A %s(%s, %s, %s,);\n",get_next_inst(),
					d_inp->id_name,
					clk->id_name,q->id_name);
}

void get_2to1_mux(struct id_node * i1,struct id_node * i2,
					struct id_node * op,struct id_node * ctrl)
{
	struct id_node * temp1 = get_next_temp(NULL,NULL);
	struct id_node * temp2 = get_next_temp(NULL,NULL);
	struct id_node * temp3 = get_next_temp(NULL,NULL);
	
	sprintf(out_str + strlen (out_str),"INRB %s(%s, %s);\n",get_next_inst(),ctrl->id_name,
										temp1->id_name);
	sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",get_next_inst(),ctrl->id_name,
										i1->id_name,temp2->id_name);
	sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",get_next_inst(),temp1->id_name,
										i2->id_name,temp3->id_name);
	sprintf(out_str + strlen (out_str),"OR2 %s(%s, %s, %s);\n",get_next_inst(),temp2->id_name,
										temp3->id_name,op->id_name);
}

#define new_temp (get_next_temp (NULL, NULL) -> id_name)
char * get_comparator (struct id_node * id, char * bitstring)
	// returns a circuit for checking equality of a bitvector with
	// some constant string; used in synthesis of case statement
{
	int i;
	int sign = id->start > id->end ? -1 : 1;
	char * res = NULL, * prev_temp;

	for (i = 0; bitstring[i]; i++)
	{
		if (bitstring[i] == '1')
		{
			if (!res)
			{
				res = (char *)malloc(100);
				sprintf (res, "%s[%d]", id->id_name, (sign * i) + id -> start);
			}
			else
			{
				prev_temp = res;
				res = new_temp;
				sprintf(out_str + strlen (out_str), "AND2 %s(%s, %s[%d], %s);\n", 
					get_next_inst(),prev_temp, 
					id->id_name, (sign * i) + id -> start, res);
			}				
		}
		else if (bitstring[i] == '0')
		{
			if (!res)
			{
				res = (char *)malloc(100);
				sprintf (res, "%s[%d]", id->id_name, (sign * i) + id -> start);
			}
			else
			{
				prev_temp = res;
				res = new_temp;
				sprintf out_str + strlen (out_str)stdout, "INRB %s(%s, %s);\n", get_next_inst(),
								prev_temp, res);
				prev_temp = res;
				res = new_temp;
				sprintf out_str + strlen (out_str)stdout, "AND2 %s(%s, %s[%d], %s);\n", 
					get_next_inst(),prev_temp, 
					id->id_name, sign * i + id -> start, res);
			}
		}
	}
	return res;
				
}



//#define get_id_node (id) {id = (struct id_node *) malloc(sizeof(struct id_node)); 
//		id -> id_name = NULL; 
//		id -> start = -1; 
//		id -> end = -1 
//		}
struct id_node * get_id_node(char * name)
{
	struct id_node * temp = (struct id_node *) malloc(sizeof(struct id_node));
	temp->id_name = (char *) malloc(20);
	strcpy(temp->id_name, name);
	temp->start = -1;
	temp->end = -1;
	temp->next = NULL;
	return temp;
}	
		
									
// function to get premux logic (c1,~c1&c2,~c1&~c2&c3,....)
struct id_node * premux(struct id_node * case_exp, struct id_node * bitstrings )
{
	struct id_node * res = get_id_node(NULL); 
	char * curr_node = new_temp; 
	char * acc_neg = new_temp;
	char * curr_neg;
	char * temp_neg;
	struct id_node * temp;	

	// Assumption   NO DEFAULT CASE IN BITSTRING.



	
	if(!bitstrings||!case_exp)
		return NULL;
	
	curr_node = get_comparator(case_exp,bitstrings->id_name);
	res->id_name = curr_node;
	sprintf(out_str + strlen (out_str),"INRB %s(%s, %s);\n",get_next_inst(),curr_node, acc_neg);
	
	bitstrings = bitstrings->next;
	while (bitstrings)
	{
		curr_node = get_comparator(case_exp,bitstrings->id_name);
		temp = get_next_temp(NULL,NULL);
		sprintf(out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",get_next_inst(),acc_neg,
											curr_node,temp->id_name);
		temp->next = res;
		res = temp;		
		if(bitstrings->next)
		{
			temp_neg = new_temp;
			curr_neg = new_temp;
			sprintf(out_str + strlen (out_str),"INRB %s(%s, %s);\n",get_next_inst(),curr_node, curr_neg);
		sprintf (out_str + strlen (out_str),"AND2 %s(%s, %s, %s);\n",get_next_inst(),acc_neg,
												curr_neg,temp_neg);
			acc_neg = temp_neg;
		}
		bitstrings = bitstrings->next;

	}		

return res;
}

struct id_node * reverse(struct id_node * list) 
{
	struct id_node * iterator;
	struct id_node * rlist = list;
	if (!list) return NULL;
	iterator = list->next;
	rlist->next = NULL;
	while (iterator)
	{
		list = iterator->next;
		iterator->next = rlist;
		rlist = iterator;
		iterator = list;
	}
	return rlist;
}	



struct id_node * gen_mux (struct id_node * lhs, struct id_node * rhs, 
		struct id_node * sss, struct id_node * condition, 
		struct id_node* fullsss,int onlymux)
	/*
	   case (cond)
	   		sss1:
				lhs1 = rhs1;
			sss2:
				lhs2 = rhs2;
	*/
{
	struct id_node * res_head = NULL;
	struct id_node * res = NULL;
	char  *negres, *comp_res, *curr_neg, *temp;
	char * def_rhs = NULL;
	int match = 0;
	
	while (fullsss)
	{
/*		if( sss && ((!(sss->id_name)&&
			!(fullsss->id_name))||!strcmp (fullsss->id_name, sss->id_name)))
		   match = 1;
		else
			match = 0;	
*/	
		if (sss)
		{
			if (sss->id_name)
				if(fullsss->id_name)
					match = !strcmp (fullsss->id_name, sss->id_name);
				else
					match = 0;
			else
				if(fullsss->id_name)
					match = 0;
				else
				{
					match = 1;
					def_rhs = rhs->id_name;	
					rhs = rhs->next;
					sss = sss->next;
					continue;
				}
		}
		else
			match = 0;
//		match = sss ? !strcmp (fullsss->id_name, sss->id_name) : 0;
/*		if (match && !sss->id_name)
		{
			def_rhs = rhs->id_name;	
			if (match)
			{
				rhs = rhs->next;
				sss = sss->next;
			}
			fullsss = fullsss->next;
			continue;
		}
*/
		if(!fullsss->id_name) 
		{
			fullsss = fullsss->next;
			continue;
		}
		if (!res_head)
		{
			res = get_next_temp(NULL,NULL);
			comp_res = get_comparator (condition, fullsss->id_name);
			negres = new_temp;
			sprintf(out_str + strlen (out_str), "INRB %s(%s, %s);\n", get_next_inst(),
								comp_res, negres);
			sprintf(out_str + strlen (out_str), "AND2 %s(%s, %s, %s);\n",get_next_inst(),
				comp_res,match?rhs->id_name:lhs->id_name, 
				res->id_name);
			res_head = res;
		}
		else
		{
			res = get_next_temp(NULL,NULL);
			comp_res = get_comparator (condition, fullsss->id_name);
			curr_neg = new_temp;
			sprintf (out_str + strlen (out_str), "INRB %s(%s, %s);\n", get_next_inst(),comp_res,
									 curr_neg);
			temp = new_temp;
			sprintf (out_str + strlen (out_str), "AND2 %s(%s, %s, %s);\n", get_next_inst(),
									comp_res, negres, temp);
			sprintf (out_str + strlen (out_str), "AND2 %s(%s, %s, %s);\n", get_next_inst(),
						temp,match?rhs->id_name:lhs->id_name, res->id_name);
			res->next = res_head;
			res_head = res;
						
			temp = new_temp;
			sprintf (out_str + strlen (out_str), "AND2 %s(%s, %s, %s);\n", get_next_inst(),
						curr_neg, negres,temp);
			negres = temp;
		}
		if (match)
		{
			rhs = rhs->next;	
			sss = sss->next;
		}
		fullsss = fullsss->next;	
	}

	//assert (def_rhs);		// default was encountered
	
	res = get_next_temp(NULL,NULL);
	sprintf (out_str + strlen (out_str), "AND2 %s(%s, %s, %s);\n", get_next_inst(),negres, 
		def_rhs?def_rhs:lhs->id_name, res->id_name);
	res->next = res_head;
	res_head = res;
	if(onlymux)	
		return optimise(res_head,OR,lhs);
	else
	{
		res = optimise(res_head,OR,NULL);
		sprintf (out_str + strlen (out_str), "FD1S1A %s(%s, 1, %s, %s);\n", get_next_inst(),
								res->id_name, 
								lhs->id_name, "TEMP");
		return res;
				
	}	
}


// gets the lhs corresponding to the default value of the case alternatve.
struct id_node * find_default(struct id_node * list, struct id_node * alts )
{
	while(list)
	{
		if(! (alts->id_name))
			break;
		list = list->next;
		alts = alts->next;
	}
	return list;
}	

struct id_node * dup_list(struct id_node * s);

void convert_case(struct id_node * rhs, struct id_node * lhs, struct id_node *sss,
								struct id_node * condition)
{
	struct id_node * iterator;
	struct id_node * muxnode;
	
	struct id_node * lit,* rit,* sit;
	struct id_node * llist = NULL, * rlist = NULL, * slist = NULL;
	struct id_node * lprev, * rprev, * sprev;
	struct id_node * lhead, * rhead, * shead;
	struct id_node * fullsss;

	fullsss = dup_list (sss);

	iterator = lhs;
	muxnode = find_default(lhs,sss);
	if(muxnode)
	{
		while(iterator && ! strcmp(iterator->id_name,muxnode->id_name))
			iterator = iterator->next;

		if(iterator)
			muxnode = NULL;
	}
	if(muxnode)
		iterator = gen_mux(lhs, rhs, sss, condition, fullsss, 1);	
	else
	{
		//generate latches
		lhead = lhs;
		rhead = rhs;
		shead = sss;

		while(lhead)
		{
			assert(rhead);
			assert(shead);
			
			//set lit,lprev ... to the next value

			lit = lhead->next;
			lprev = lhead;
			rit = rhead->next;
			rprev = rhead;
			sit = shead->next;
			sprev = shead;
				
			while(lit)
			{
				assert(rit);
				assert(sit);
				
				if(! strcmp(lit->id_name,lhead->id_name))
				{
					lprev->next = lit->next;
					lit->next = llist;
					llist = lit;
					lit = lprev->next;
					
					rprev->next = rit->next;
					rit->next = rlist;
					rlist = rit;
					rit = rprev->next;
					
					sprev->next = sit->next;
					sit->next = slist;
					slist = sit;
					sit = sprev->next;
				}
				else
				{
					lit = lit->next;
					rit = rit->next;
					sit = sit->next;

					lprev = lprev->next;
					rprev = rprev->next;
					sprev = sprev->next;
				}
			}
			assert(!rit);
			assert(!sit);
			
			llist = reverse(llist);
			rlist = reverse(rlist);
			slist = reverse(slist);

			lprev = lhead;
			rprev = rhead;
			sprev = shead;

			lhead = lhead->next;
			rhead = rhead->next;
			shead = shead->next;
			
			lprev->next = llist;
			rprev->next = rlist;
			sprev->next = slist;
		
			llist = lprev;
			rlist = rprev;
			slist = sprev;

			gen_mux(llist,rlist,slist,condition,fullsss,0);
			
			llist = NULL;
			rlist = NULL;
			slist = NULL;
			
		}
		assert(!rhead);
		assert(!shead);

	}
}
					
void printid(struct id_node * list)
{
	while(list)
	{
		fprintf(stderr," %s %d %d", list->id_name,list->start,list->end);
		list = list->next;
	}
	fprintf(stderr,"\n");
}

struct id_node * dup_list(struct id_node * s)
{
	struct id_node * prev = NULL;
	struct id_node * new_node;
	struct id_node * first = NULL;

	while(s)
	{
		new_node = (struct id_node *) malloc(sizeof(struct id_node));
		if (!first) first = new_node;
		memcpy(new_node,s,sizeof(struct id_node));
		if (!s->id_name)
			new_node->id_name = NULL;
		else
		{
			new_node->id_name = (char *) malloc((1+strlen(s->id_name))*sizeof(char));
			strcpy(new_node->id_name,s->id_name);
		}
		new_node->next = NULL;

		if (prev)
			prev->next = new_node;
		prev = new_node;
		s = s->next;
	}
	return first;
}

int find_min_width(struct id_node * list1,struct id_node * list2)
{
	int min = RAND_MAX;
	while(list1)
	{
		min = min > abs(list1->start - list1->end) + 1?
				abs(list1->start - list1->end) + 1 : min;
		list1 = list1->next;
	}
	if(list2)	
		min = min > abs(list2->start - list2->end) + 1 ?
				abs(list2->start - list2->end) + 1 : min;
	return min;
}
void cleanup()
{
	//Reason : __TEMP_ has to be removed from get_next_temp() output

	int i;
	int max_temp = atoi(get_next_temp(NULL,NULL)->id_name + 7);

	sprintf(out_str + strlen (out_str),"\nwire ");	
	for(i = 0;i < max_temp - 1;i++)
	{
		if(i%5 == 0 && i) sprintf(out_str + strlen (out_str),";\nwire ");
		else if(i) sprintf(out_str + strlen (out_str),",");
		sprintf(out_str + strlen (out_str),"__TEMP_%d",i);
	}
	if((i-1)%5 != 0)
		sprintf(out_str + strlen (out_str),";");
		 
}
