import java.io.*;
import java.util.StringTokenizer;

//****************** CODE GENERATION ************************************
class Codegen {
  // This is like parser in that there is a code generation object and it
  // has a method called codegen which produces the code.  Every time you
  // want to generate some code you make a new Codegen object which has the
  // ExpTree produced by the parser stored inside it.  I have written file
  // IO code for you.  This is contained in a method called generateToFile
  // which will prompt the user for the name of a file where the output
  // should go.  This method calls the method "codegen" which you will
  // write. 

  private int tempstore;
  private ExpTree tree;
  private String outFilename;
  private PrintWriter out;

  public Codegen(ExpTree t){
    tree = t;
    tempstore = 1;}

  public void generateToFile(String outFilename) {
    FileInputStream inputData;
       try {
       out = new PrintWriter (new FileWriter(outFilename));
       codegen(tree, "", false);
       out.close();
       } catch(IOException exception){
         System.out.println("IO problem. Terminating.");
         System.exit(0);}
  };

     private static String commandString(Character operChar) {
     //Given a symbol (in Character form), returns the command that should be
     //used when generating code.
         String operStr = operChar.toString();
         if (operStr.equals("+")) return "ADD";
         else if (operStr.equals("-")) return "SUBTRACT";
         else if (operStr.equals("_")) return "SUBFROM";
         else if (operStr.equals("*")) return "MUL";
         else if (operStr.equals("/")) return "DIVBY";
         else if (operStr.equals("\\")) return "DIVINTO";
         else if (operStr.equals("^")) return "POW";
         else {
             System.out.println("Error: unrecognized command: " + operChar);
             return "";
         }
     }
     
     private static Character switchOper(BinTree t) {
     //Returns the root symbol for division and subtraction to reflect change
     //in order.
         Character operChar = (Character) t.root();
         Character temp = operChar;
         String operStr = operChar.toString();
         if (operStr.equals("-")) temp = new Character("_".charAt(0));
         else if (operStr.equals("_")) temp = new Character("-".charAt(0));
         else if (operStr.equals("/")) temp = new Character("\\".charAt(0));
         else if (operStr.equals("\\")) temp = new Character("/".charAt(0));
         return temp;
     }
     
     
     private static void switchUp(BinTree t) {
     //Switches the left and right sides of a tree, and changes the root command
     //if necessary. (For instance, A/B --> B\A)
         t.SetRoot(switchOper(t));
         BinTree temp=t.left();
         t.SetLeft(t.right());
         t.SetRight(temp);
     }
     
     private static boolean associative(String oper1, String oper2) {
     //Given two operators (in String form), returns true if you can use the
     //associative property with the two operators (in that order). For example,
     //associative("+", "-") returns true because (A+B)-C=A+(B-C), but
     //associative("-", "+") returns false because (A-B)+C<>A-(B+C).
         if (oper1.equals("+"))
             return (oper2.equals("+") || oper2.equals("-") || oper2.equals("_"));
         else if (oper1.equals("*"))
             return (oper2.equals("*") || oper2.equals("/") || oper2.equals("\\"));
         else return false;
     }
  
     private boolean codegen(ExpTree t, String lastOper, boolean rightTree){
     //t is the Tree to generate code for.
     //lastOper is a String representing the operator from the calling tree,
     //only used if rightTree is true.
     //rightTree is whether t is a right tree of the calling tree.
         
         //OPTIMIZATION:
         //(1) If the right side is longer than the left side, switch them.
         if (t.left().length() < t.right().length()) switchUp(t);
         //(2) Otherwise, if the left side "associates," but the right side does
         //not, switch them, because association is only used when descending
         //down the right side of the tree. Don't bother switching if the right
         //side is just a variable, though, because this will not improve, and
         //may negatively affect, the quality resulting code.
         else if (!(t.right() instanceof Var) && associative(t.root().toString(),t.left().root().toString()) && !associative(t.root().toString(),t.right().root().toString())) {
             switchUp(t);
         }
         
         boolean storeStuff = false; //used to indicate whether a "STORE"
                                     //command was used, so the calling tree
                                     //knows where to find its previous results
         
         if (t instanceof Oper) {
             String firstAction = "LOAD "; //Action to be taken if left is a Var
             if (rightTree) {
                 if (associative(lastOper, t.root().toString()))
                 //If we can use associative property, then we might not need
                 //to STORE anything
                 {
                     if (!(t.left() instanceof Var)) {
                     //If left is a Var, then we have to STORE, so we can load it
                         out.println("STORE " + tempstore++);
                         storeStuff = true;
                     }
                     //Otherwise, we can execute the command from the calling tree
                     else firstAction = commandString(new Character(lastOper.charAt(0))) + " ";
                 }
                 else {
                 //If we can't use associative property, then we need to store
                 //whatever the calling tree did.
                     out.println("STORE " + tempstore++);
                     storeStuff = true;
                 }
             }
             if (t.left() instanceof Var) {
             //If left is a Var, then do something with it (LOAD or perform
             //some operation if we are using associativity.
                 String rightStr = t.left().root().toString();
                 out.println(firstAction + rightStr);
             }
             //Otherwise, call codegen() on left
             else codegen((ExpTree) t.left(), t.root().toString(), false);

             if (t.right() instanceof Var) {
             //If right is a Var, then we just perform our operation with it
                 String rightStr = t.right().root().toString();
                 out.println(commandString((Character) t.root()) + " " + rightStr);
             }
             else {
             //Otherwise, we need to go down the right tree:
                 boolean storedStuff = codegen((ExpTree) t.right(), t.root().toString(), true);
                 if (storedStuff) {
                 //If the right tree stored our previous result (from the left)
                 //then we need to run our command on the stored value. But we
                 //need to switch the operator, because we waited until after
                 //we did stuff on the right to perform the operation.
                     out.println(commandString(switchOper((BinTree) t)) + " " + --tempstore);
                 }
                 //Otherwise, they took care of our command.
             }
         }
         else {
             out.println("Error--non-operator node!");
         }
         return storeStuff; //Let the calling tree know whether we stored stuff
     }//end method codegen

    public static void main(String[] args){
    SymbolTable S = SymbolTable.getdefs(args[0]);
    char[] Data = Tokenizer.scan(args[1]);
    Parser P = new Parser(Data);
    ExpTree E = P.parse();
    Codegen G = new Codegen(E);   
    G.generateToFile(args[2]);
    }//end method main
}// end Codegen

  
  



      

