datatype circuit = CRES of real
		 | VRES of string
		 | SER of circuit * circuit 
		 | PAR of circuit * circuit 

datatype token   = VAR of string | NUMBER of real | PARALLELSIGN | SERIESSIGN 

(* Higher-order recursive function for circuits 
vr,cr,s,p are the functions applied for each constructor 
vr for vRes, cr for cRes, s for Ser and p for Par *) 

fun mapCirc (vr,cr,s,p) (VRES x) = vr x 
  | mapCirc (vr,cr,s,p) (CRES x) = cr x 
  | mapCirc (vr,cr,s,p) (SER(c1,c2)) = s (mapCirc(vr,cr,s,p) c1, 
					  mapCirc(vr,cr,s,p) c2)
				       
  | mapCirc (vr,cr,s,p) (PAR(c1,c2)) = p (mapCirc(vr,cr,s,p) c1, 
					  mapCirc(vr,cr,s,p) c2)

fun serSimplify(CRES r1, CRES r2) = CRES(r1+r2)
  | serSimplify(c1, c2) = SER(c1,c2);

fun parSimplify(CRES r1, CRES r2) = CRES(1.0/(1.0/r1 + 1.0/r2))
  | parSimplify(c1,c2) = PAR(c1,c2);

val toInfix = mapCirc (fn s:string => s,
		       fn n => Real.toString(n), 
		       fn(s1,s2)=>"(" ^ s1 ^" - " ^ s2 ^ ")",
		       fn(s1,s2)=>"(" ^ s1 ^" | " ^ s2 ^ ")");

val countCons = mapCirc (fn _ => 0, fn _ => 1, op+, op+);
      
val simplify = mapCirc (fn s => VRES s, 
		        fn n => CRES n, 
		        serSimplify,
		        parSimplify);

(* tokenize list of strings seperated by whitespace *) 
fun str2token "|" = PARALLELSIGN
  | str2token "-" = SERIESSIGN
  | str2token s   = if (Char.isAlpha(hd(explode(s)))) then VAR(s)
		    else NUMBER(valOf(Real.fromString(s)))

fun readTokens str = map str2token (String.tokens Char.isSpace str);

(* parse list of token to abstract syntax tree *) 
fun parse(NUMBER(n)::ts) = (CRES(n), ts)
  | parse(VAR(s)::ts) =    (VRES(s), ts)
  | parse(PARALLELSIGN::ts) = let val (tr,ts') = parse(ts) 
				  val (tr',ts'') = parse(ts')
			      in 
				  (PAR(tr,tr'), ts'')
			      end
  | parse(SERIESSIGN::ts) = let val (tr,ts') = parse(ts) 
				val (tr',ts'') = parse(ts')
			    in 
				  (SER(tr,tr'), ts'')
			    end
  | parse _ = (CRES(0.0),[])

(* process abstract syntax tree to generate results *)
fun process s = let val (atr,ts) = parse(readTokens(s))
		    val c = countCons(atr)
		    val str = simplify(atr)
		    val sc = countCons(str)
                in
		    "--- Circuit --- \n" ^
		    "CountCons : " ^ Int.toString(c) ^ "\n" ^
		    "Infix     : " ^ toInfix(atr) ^ "\n" ^
		    "CountCons : " ^ Int.toString(sc) ^ "\n" ^
		    "Infix     : " ^ toInfix(str) ^ "\n"
		end;

(* file IO functions *) 
fun readFile(output,instr) = case (TextIO.inputLine instr) of 
				 NONE => output
			       | SOME line => readFile(output^process(line),instr);

fun writeFile(input,ofname) =  let val outstr = TextIO.openOut ofname
			       in
				   TextIO.output(outstr, input);
				   TextIO.closeOut outstr
			       end;

fun main(instr,outstr) = writeFile(readFile("",TextIO.openIn(instr)), outstr); 
