// ultra simple RPN Calculator
// project created on 24.03.2006 at 08:27
// #define DEBUG_OUTPUT

using System;

// Koten für Stack
class NumNode
    {
    public NumNode Next;
    public double dftValue;
    }

// Rechner
class CalculatorClass

    {
    // types
    public enum Cmd {Push, Pop, Quit, Add, Sub, Mul, Div, Chs, Clear, Help, Inv, Sin, Cos, Sqrt, Sq, Pow};
    
    // methods

    // --------------------------------------------------------------   
    // M A I N 
    public static void Main(string[] args)
        {
        Calculate();
        }
        
    // --------------------------------------------------------------   
    // Arbeitsfunktion
    public static void Calculate()
        {
        NumNode StackHead = new NumNode();
        
        stackInit(StackHead);
        Console.WriteLine("HP-00S Calculator\n<?> für Hilfe");

        for (bool fRun = true ; fRun ; )
            {
            double dftTemp;
            
            switch (inputParse(StackHead))
                {
                case Cmd.Push:
                    // push hat ja schon in inputParse() stattgefunden 
                    break;
                    
                // Binaere Operatoren
                case Cmd.Add:
                    stackPushAndShow(StackHead, stackPop(StackHead) + stackPop(StackHead)); 
                    break;

                case Cmd.Sub:
                    // RPN sieht hier gerne eine andere Reihenfolge
                    dftTemp = stackPop(StackHead);
                    stackPushAndShow(StackHead, stackPop(StackHead) - dftTemp); 
                    break;

                case Cmd.Mul:
                    stackPushAndShow(StackHead, stackPop(StackHead) * stackPop(StackHead)); 
                    break;

                case Cmd.Div:
                    // RPN sieht hier gerne eine andere Reihenfolge
                    dftTemp = stackPop(StackHead);
                    if (dftTemp != 0.0)
                        stackPushAndShow(StackHead, stackPop(StackHead) / dftTemp);
                    else
                        Console.WriteLine("ERR: DIV/0"); 
                    break;

                case Cmd.Pow:
                    // RPN sieht hier gerne eine andere Reihenfolge
                    dftTemp = stackPop(StackHead);
                    stackPushAndShow(StackHead, Math.Pow( stackPop(StackHead), dftTemp )); 
                    break;
                
                //  unaere Operatoren
                case Cmd.Chs:
                    stackPushAndShow(StackHead, -stackPop(StackHead));
                    break;

                case Cmd.Inv:
                    dftTemp = stackPop(StackHead);
                    if (dftTemp != 0.0)
                        stackPushAndShow(StackHead, 1.0 / dftTemp);
                    else
                        Console.WriteLine("ERR: DIV/0"); 
                    break;

                case Cmd.Cos:
                    stackPushAndShow(StackHead, Math.Cos(stackPop(StackHead)));
                    break;

                case Cmd.Sin:
                    stackPushAndShow(StackHead, Math.Sin(stackPop(StackHead)));
                    break;

                case Cmd.Sq:
                    dftTemp = stackPop(StackHead);
                    stackPushAndShow(StackHead, dftTemp * dftTemp);
                    break;

                case Cmd.Sqrt:
                    dftTemp = stackPop(StackHead);
                    if (dftTemp >= 0.0)
                        stackPushAndShow(StackHead, Math.Sqrt(dftTemp));
                    else
                        Console.WriteLine("ERR: SQRT(0)"); 
                    break;

                // Logistikfunktionen
                case Cmd.Clear:
                    stackInit(StackHead);
                    break;

                case Cmd.Quit:
                    fRun = false;
                    break;
                
                default:
                    helpShow();
                    break; 
                }
                
#if DEBUG_OUTPUT
            stackShow(StackHead);

#endif
            }
        }
        
    // --------------------------------------------------------------   
    // Eingabeverarbeitung
    public static Cmd inputParse(NumNode Head)
        {
        int    nChar;
        string strZahl = "";
        Cmd     cmdReturn = Cmd.Quit;
        
        for (bool fRun = true ; fRun ; )
            {
            fRun = false;
                            
            nChar = Console.Read();
            switch (nChar)
                {
                // Enter
                case 10: 
                    if (strZahl.Length > 0)
                        cmdReturn = Cmd.Push;
                    else
                        fRun = true;    
                    break;
                
                // Zahl;    
                case '0':   
                case '1':   
                case '2':   
                case '3':   
                case '4':   
                case '5':   
                case '6':   
                case '7':   
                case '8':   
                case '9':   
                case ',':
                case 'e':
                case 'E':
                    fRun     = true;
                    strZahl += Convert.ToChar( nChar );
                    break;
                    
                // soll auch ein 
                case '.':
                    fRun     = true;
                    strZahl += ',';
                    break;
                    
                case '+':
                    cmdReturn = Cmd.Add;
                    break;
                            
                case '-':
                    cmdReturn = Cmd.Sub;
                    break;

                case '*':
                    cmdReturn = Cmd.Mul;
                    break;

                case '/':
                    cmdReturn = Cmd.Div;
                    break;

                case 'X':
                case 'x':
                    cmdReturn = Cmd.Chs;
                    break;

                case 'D':
                case 'd':
                    cmdReturn = Cmd.Clear;
                    break;

                case 'W':
                case 'w':
                    cmdReturn = Cmd.Sqrt;
                    break;

                case 'Q':
                case 'q':
                    cmdReturn = Cmd.Sq;
                    break;

                case 'P':
                case 'p':
                    cmdReturn = Cmd.Pow;
                    break;

                case 'S':
                case 's':
                    cmdReturn = Cmd.Sin;
                    break;

                case 'C':
                case 'c':
                    cmdReturn = Cmd.Cos;
                    break;

                case 'K':
                case 'k':
                    cmdReturn = Cmd.Inv;
                    break;

                case '?':
                    cmdReturn = Cmd.Help;
                    break;
                    
                case '#':
                    cmdReturn = Cmd.Quit;
                    break;
                
                default:    
#if DEBUG_OUTPUT
                    Console.WriteLine("Unmapped key {0}", nChar);
#endif  
                    cmdReturn = Cmd.Help;
                    break;
                }
            }

        if (strZahl.Length > 0)
            {
            double dftInputRegister = 0.0;
            
            dftInputRegister = Convert.ToDouble (strZahl);

#if DEBUG_OUTPUT
            Console.WriteLine(" > {0}", dftInputRegister);
#endif

            if (Cmd.Push == cmdReturn)
                {
                stackPush(Head, dftInputRegister);
                }
                
                
            strZahl = "";                       
            }

        return cmdReturn;
        }

    // ******************************************************************************************   
    // Stackhandling
    
    // leeren Stack anlegen 
    public static void stackInit(NumNode Head)
        {
        NumNode End  = new NumNode();
        
        End.Next = null;
        Head.Next = End;
        }   

    // --------------------------------------------------------------   
    // push 

    public static void stackPush(NumNode Head, double dftValue)
        {
        NumNode Node = new NumNode();
        
        Node.dftValue = dftValue;
        Node.Next     = Head.Next;
        
        Head.Next = Node;
        }   

    public static void stackPushAndShow(NumNode Head, double dftValue)
        {
        stackPush(Head, dftValue);
        Console.WriteLine("==> {0}",dftValue);
        }

    // --------------------------------------------------------------   
    // pop  
    public static double stackPop(NumNode Head)
        {
        double dftValue = 0.0;
        NumNode Node = Head.Next;
        
        // wenns net des Schwänzle is
        if  (Node.Next != null)
            {
            Head.Next = Node.Next;
            dftValue = Node.dftValue;
            }
        else
            {
            Console.WriteLine("ERR: Stack is EMPTY");
            }   
        return dftValue;
        }   

    // --------------------------------------------------------------   
    // ganzen stack anzeigen
    public static void stackShow(NumNode Head)
        {
        Console.WriteLine(" ***** STACK *****");
        for (NumNode Node = Head.Next ; Node.Next != null ; Node = Node.Next )
            {
            Console.WriteLine(Node.dftValue);
            }
        Console.WriteLine(" *****************");
        }

    // --------------------------------------------------------------   
    // Top of stack anzeigen    
    public static void stackTopShow(NumNode Head)
        {
        NumNode Node = Head.Next;
        if( Node.Next != null )
            {
            Console.WriteLine("==> {0}",Node.dftValue);
            }
        }

    // --------------------------------------------------------------   
    // Top of stack anzeigen    
    public static void helpShow()
        {
        Console.WriteLine("Hilfe zum HP-00S\n");
        
        Console.WriteLine("  # ... Beenden");
        Console.WriteLine("  d ... Clear stack\n");
        
        Console.WriteLine("  + ... Addition");
        Console.WriteLine("  - ... Subtraktion");
        Console.WriteLine("  * ... Multiplikation");
        Console.WriteLine("  / ... Division\n");

        Console.WriteLine("  x ... Vorzeichenwechsel");
        Console.WriteLine("  w ... Quadratwurzel");
        Console.WriteLine("  q ... Quadrat\n");
        Console.WriteLine("  k ... Kehrwert\n");
        Console.WriteLine("  p ... Potenz\n");

        Console.WriteLine("  s ... Sinus");
        Console.WriteLine("  c ... Cosinus");

        }
    } //class

syntax highlighted by Code2HTML, v. 0.9.1