Top >コンソール・アプリケーション集

逆ポーランド記法電卓 C言語

#include    <stdio.h>
#include    <conio.h>
#include    <math.h>


#define     STACK_SIZE  10  // スタックサイズ
#define     NUM_DIGITS  8   // 最大桁数

/**************************************************
* 入力処理の結果
**************************************************/

typedef enum _OPERATION
{
    OPE_PLUS,       // 足し算
    OPE_MINUS,      // 引き算
    OPE_MULTIPLY,   // 掛け算
    OPE_DIVIDE,     // 割り算
    OPE_INVERSION,  // 符号反転
    OPE_CLEAR,      // クリア
    OPE_ENTER,      // 入力
    OPE_EXIT        // 終了
}OPERATION;

/**************************************************
* スタックに関するエラーの内容
**************************************************/

typedef enum _STACK_ERROR
{
    ERR_NONE,       // エラーなし
    ERR_OVERFLOW,   // オーバーフロー
    ERR_EMPTY       // スタックが空
}STACK_ERROR;

/**************************************************
* スタックを実現する構造体
**************************************************/

typedef struct
{
    double      values[STACK_SIZE]; // 数値配列
    int         count;              // 要素数
    STACK_ERROR error;              // エラー内容
}CALC_STACK;

///////////////////////////////////////////////////
// スタックに対するPush
// pstack:CALC_STACK構造体へのポインタ
// value:Pushする数値
///////////////////////////////////////////////////
void Push( CALC_STACK* pstack, double value)
{
    if (pstack->count < STACK_SIZE)
        pstack->values[pstack->count++] = value;
    else
        pstack->error = ERR_OVERFLOW;
}

///////////////////////////////////////////////////
// スタックに対するPop
// pstack:CALC_STACK構造体へのポインタ
// return:Popされた数値
///////////////////////////////////////////////////
double Pop( CALC_STACK* pstack)
{
    if (pstack->count > 0)
    {
        pstack->count--;
        return pstack->values[pstack->count];
    }
    else
    {
        pstack->error = ERR_EMPTY;
        return 0.0;
    }
}

///////////////////////////////////////////////////
// 入力処理
// pstack:CALC_STACK構造体へのポインタ
// return:OPERATION
///////////////////////////////////////////////////
OPERATION Input(CALC_STACK* pstack)
{
    char        number[NUM_DIGITS + 1];
    int         cntnum = 0;
    OPERATION   ope = OPE_ENTER;

    for (;;)
    {
        int ch = _getche(); // 文字を入力

        if ('0' <= ch && ch <= '9' || ch == '.')
        {
            // 数字と小数点の場合

            if (cntnum < NUM_DIGITS)
            {
                number[cntnum++] = (char)ch;
                number[cntnum] = 0;
            }
        }
        else{
            // 演算の場合

            if (ch == '+')
                ope = OPE_PLUS;
            else if (ch == '-')
                ope = OPE_MINUS;
            else if (ch == '*')
                ope = OPE_MULTIPLY;
            else if (ch == '/')
                ope = OPE_DIVIDE;
            else if (ch == '!')
                ope = OPE_INVERSION;
            else if (ch == 'c' || ch == 'C')
                ope = OPE_CLEAR;
            else if (ch == 'q' || ch == 'Q')
                ope = OPE_EXIT;

            break;  // 入力を終了
        }
    }

    // 数字の入力があれば、スタックにプッシュする。
    if (cntnum > 0)
        Push(pstack, atof(number));

    return ope;
}

///////////////////////////////////////////////////
// 電卓画面を表示
///////////////////////////////////////////////////
void ShowCalculator( CALC_STACK stack)
{
    int     i;

    printf("\n>>> RPN Calculator >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
    printf("\n>>>  +:加 -:減 *:乗 /:除 !:符号 c:削除 q:終了  >>>\n");

    // スタックの内容を表示する
    for (i = 0; i < stack.count; i++)
    {
        printf("%2d:%f\n", stack.count - i, stack.values[i]);
    }
}

///////////////////////////////////////////////////
// main
///////////////////////////////////////////////////
void main(void)
{
    CALC_STACK  stack;

    // CALC_STACK構造体の初期化
    stack.count = 0;
    stack.error = ERR_NONE;

    for (;;)
    {
        OPERATION operation;

        // 電卓画面を表示
        ShowCalculator(stack);

        // 入力
        operation = Input(&stack);

        if (stack.error == ERR_OVERFLOW)
        {
            // オーバーフローの場合
            printf("\nOverflow!\n");
            stack.error = ERR_NONE;
            continue;
        }

        // 必要な個数の数値をポップして演算を施し、結果をプッシュする

        if (operation == OPE_INVERSION || operation == OPE_CLEAR){
            // 必要とする数値が1つの操作

            if (stack.count < 1){
                printf("\nError!\n");
            }
            else{
                double n = Pop(&stack); // ポップする

                if (operation == OPE_INVERSION)     // 符号反転
                    Push(&stack, n * (-1.0));
            }
        }
        else if (operation == OPE_PLUS || operation == OPE_MINUS
            || operation == OPE_MULTIPLY || operation == OPE_DIVIDE)
        {
            // 必要とする数値が2つの操作

            if (stack.count < 2){
                printf("\nError!\n");
            }
            else{
                double  n1 = Pop(&stack);   // ポップする
                double  n2 = Pop(&stack);   // ポップする

                if (operation == OPE_PLUS)          // 加算
                    Push(&stack, n1 + n2);
                else if (operation == OPE_MINUS)    // 減算
                    Push(&stack, n2 - n1);
                else if (operation == OPE_MULTIPLY) // 乗算
                    Push(&stack, n1 * n2);
                else if (operation == OPE_DIVIDE)   // 除算
                {
                    if (n1 == 0.0)  // 0での除算
                        printf("\nDivide by Zero!\n");
                    else
                        Push(&stack, n2 / n1);
                }
            }
        }
        else if (operation == OPE_EXIT)
        {
            // プログラムの終了
            break;
        }
    }
}
PAPER BOWL
NEZEN