interface Expr
{
    void printPrefix () ;
    void printInfix () ;
    void printInfix (ExprOp father, boolean iAmRight) ; 
                          // fonction auxiliaire pour printInfix ()
    int value () ;
    Expr derive (char v) ;
    String toString () ;
    String toString2 () ;
    void addToString (StringBuffer sb) ;
}

class ExprInt implements Expr
{
    int intVal ;
    
    public ExprInt (int v) {
        intVal = v ;
    }

    public void printPrefix () {
        System.out.print (this) ; // appel implicite de toString()
    }

    public void printInfix () {
        System.out.print (this) ;
    }

    public void printInfix (ExprOp father, boolean iAmright) {
        System.out.print (this) ;
    }

    public int value () {
        return intVal ;
    }

    static Expr zero = new ExprInt (0) ;

    public Expr derive (char v) {
        return zero ;
    }

    public String toString () {
        return "" + intVal ;
    }

    public String toString2 () {
        return "" + intVal ;
    }

    public void addToString (StringBuffer sb) {
        sb.append (intVal) ;
    }
}

class ExprVar implements Expr
{
    char var ;

    ExprVar (char v) {
        var = v ;
    }

    public void printPrefix () {
        System.out.print (this) ;
    }

    public void printInfix () {
        System.out.print (this) ;
    }

    public void printInfix (ExprOp father, boolean iAmright) {
        System.out.print (this) ;
    }

    public int value () {
        throw new Error ("Valeur d'une variable : " + var) ;
    }

    static Expr zero = new ExprInt (0) ;
    static Expr un = new ExprInt (1) ;

    public Expr derive (char v) {
        if (v == var) return un ;
        else return zero ;
    }

    public String toString () {
        return "" + var ;
    }

    public String toString2 () {
        return "" + var ;
    }

    public void addToString (StringBuffer sb) {
        sb.append (var) ;
    }
}

class ExprOp implements Expr
{
    char op ;
    Expr left, right ;

    ExprOp (char o, Expr l, Expr r) {
        op = o ;
        left = l ;
        right = r ;
    }
    
    public void printPrefix () {
        System.out.print (this) ;
    }

    // Avec peu de parenth`eses :
    public void printInfix () {
        left.printInfix (this, false) ;
        System.out.print (" " + op + " ") ;
        right.printInfix (this, true) ;
    }

    public void printInfix (ExprOp father, boolean iAmRight) {
        boolean parentheses = 
            op != '*' && (father.op == '*' 
                          || (father.op == '-' && iAmRight)) ;
        if (parentheses) System.out.print ("(") ;
        left.printInfix (this, false) ;
        System.out.print (" " + op + " ") ;
        right.printInfix (this, true) ;
        if (parentheses) System.out.print (")") ;
    }

    public int value () {
        switch (op) {
            case '+': return left.value () + right.value () ;
            case '-': return left.value () - right.value () ;
            case '*': return left.value () * right.value () ;
            default:
                throw new Error ("Op'eration inconnue : " + op) ;
        }
    }

    public Expr derive (char v) {
        Expr dl = left.derive (v) ;
        Expr dr = right.derive (v) ;
        switch (op) {
            case '+': return new ExprOp ('+', dl, dr) ;
            case '-': return new ExprOp ('-', dl, dr) ;
            case '*': 
                return new ExprOp ('+',
                                   new ExprOp ('*', dl, right),
                                   new ExprOp ('*', left, dr)) ;
            default:
                throw new Error ("Op'eration inconnue : " + op) ;
        }
    }

    public String toString2 () {
        return op + " " + left.toString2() + " " + right.toString2() ;
    }

    public String toString () {
        StringBuffer sb = new StringBuffer () ;
        addToString (sb) ;
        return sb.toString () ;
    }

    public void addToString (StringBuffer sb) {
        sb.append (op) ;
        sb.append (' ') ;
        left.addToString (sb) ;
        sb.append (' ') ;
        right.addToString (sb) ;
    }
}


class Calcul
{

    static char getChar () {
        try { // On essaye de lire un caract`ere par System.in.read() :
            return (char) System.in.read () ;
        } catch (java.io.IOException e) { // En cas de probl`eme :
            throw new Error ("Probl`eme d'entr'ee sortie.") ;
        } 
    }

    static Expr readPrefix () {
        char c = getChar () ;
        if (Character.isWhitespace (c))
            return readPrefix () ;
        if (Character.isDigit (c))
            return new ExprInt (Character.getNumericValue (c)) ;
        if (Character.isLetter (c))
            return new ExprVar (c) ;
        if (c == '+' || c == '-' || c == '*') {
            Expr l = readPrefix () ;
            Expr r = readPrefix () ;
            return new ExprOp (c, l, r) ;
        }
        throw new Error ("Caract`ere inattendu : " + c) ;
    }

    // Pour faire bigexpr.txt :
    static Expr longAdd (int n) {
        if (n <= 0) return new ExprInt (0) ;
        else return new ExprOp ('+', new ExprInt (n % 10), 
                                longAdd (n-1)) ;
    }

    public static void main (String[] args) {
        Expr e1 = new ExprOp( '*', new ExprVar('x'), new ExprInt(10));
        Expr e2 = new ExprOp( '*',
                              new ExprOp( '*', 
                                          new ExprOp( '*', 
                                                      new ExprInt(6), 
                                                      new ExprOp( '+', 
                                                                  new ExprOp( '-',
                                                                              new ExprInt(3),
                                                                              new ExprInt(2)),
                                                                  new ExprInt(1))),
                                          new ExprOp( '-',
                                                      new ExprInt(9),
                                                      new ExprInt(6))),
                              new ExprInt(2));
        /****
        e1.printPrefix () ; System.out.println() ; 
        e2.printPrefix () ; System.out.println() ; 
        e1.printInfix () ; System.out.println() ; 
        e2.printInfix () ; System.out.println() ; 
        System.out.println (e2.value()) ;
        e1.derive('x').printInfix () ; System.out.println() ; 
        readPrefix().printInfix () ; System.out.println() ; 
        ****/
        Expr e = readPrefix () ;
        // Expr e = longAdd (Integer.parseInt (args[0])) ;

        System.err.println ("Expression lue.") ;
        TC.demarrerChrono () ;
        String s = e.toString2 () ;
        System.err.println ("Tps String : " + TC.tempsChrono()
                            + " millisecondes") ;
        TC.demarrerChrono () ;
        String t = e.toString () ;
        System.err.println ("Tps StringBuffer : " + TC.tempsChrono()
                            + " millisecondes") ;
        System.err.println (s.equals (t)) ;
        // System.out.println (s) ;
    }
}
