多桁計算による四則演算 (引数による演算内容の入力)

一つ前の例題から,コマンドラインにより引数を取得して四則演算ができるものへと改良したものです.

多桁計算による四則演算 (引数による演算内容の入力)(list_91.c)
// コマンドライン引数を取得して四則演算を行うプログラム

#include "longcalc.h"

/* main関数 */
int main(int argc, char *argv[])
{
    int result = Calc_operation(argc, argv);
    if(result) ErrorMessage(result);
    return 0;
}

/* エラーメッセージ一覧 */
void ErrorMessage(int code)
{
    const char * const message_list[] = {
        "Unknown",//0...エラーではない
        "Please input a correct expression",//1...正しい計算式を入力しない場合
        "Please input the operator correctly",//2...演算子が異なる場合
        "0 division is a prohibition",//3...0除算を実行しようとした場合
        "Please input the argument correctly",//4...コマンドライン引数が指定された数と異なる場合
        "Buffers of character string overflowed.",//5...バッファオーバーフロー
    };
    printf("\nerror : %s\n", message_list[code]);
}

/** _strtoi64 の代替処理 **/
void myatol(char *p, char** end, char pValue[ORDER])
{
    char* pp = p;
    for(unsigned int i=0; i<strlen(p); i++,pp++){
        if(!isdigit(*pp)) { pValue[i] = '\0'; break; }
        pValue[i] = *pp;
    }
    *end = pp;
}

/** 文字列から多桁表現へ **/
void atolb(char* cp, short* sp)
{
    int pos, ci = 0, n = strlen(cp);
    char l[5];
    for(int i=4; i<=n; i+=4){
        memset(l,0,sizeof(char)*5);
        pos = n-i;
        if(pos < 0) pos = 0;
        strncpy(l,cp+pos,4);
        sp[N-ci++-1] = atol(l);
    }
    if(pos > 0) pos = 0;
    memset(l,0,sizeof(char)*5);
    strncpy(l,cp+pos,n%4);
    sp[N-ci-1] = atol(l);
}

void print(short* c)
{
    for(int i=0; i<N; i++) printf("%04d ",c[i]);
    printf("\n");
}

/* コマンドライン引数を配列stに格納 */
int Storage(int argc, char *argv[], char st[STRING_BUFFER_SIZE])
{
    int i=0, j=0, s=0;
    while(++i < argc) {
        s = 0;
        while(argv[i][s] != '\0') {
            //バッファオーバーフローのチェック
            if(j >= STRING_BUFFER_SIZE - 1) return 0;
            st[j] =(argv[i][s]);
            s++; ++j;
        }
    }
    st[j]='\0';
    return 1;
}

/* 空白をスキップ */
const char *Skip_parce(const char *p)
{
    if(p && *p >= 0){ while(isspace(*p)) ++p; }
    return p;
}

/* 要素解析 */
int Parse_factor(const char **p, char pValue[ORDER])
{
    *p = Skip_parce(*p); // 空白をスキップ
    if(isdigit(**p)){
        char *end;
        //*pValue = _strtoi64(*p, &end, 10);
        myatol((char*)*p,&end,pValue);
        *p = end;
        return 1;
    } else if(**p == '(') {
        ++(*p);
        if(Parse_factor(p, pValue)){
            *p = Skip_parce(*p);
            if(**p == ')') { ++*p; return 1; }
        }
    } else if(**p == '-') {
        ++(*p);
        if(Parse_factor(p, pValue)) {
            *pValue = -(*pValue); return 1;
        }
    } else if(**p == '+') {
        ++(*p);
        if(Parse_factor(p, pValue)) return 1;
    }
    return 0;//異常
}

/* 式の解析 */
int Parse(const char *expression, const char **end, char pValue[ORDER])
{
    // 要素解析
    const char *p = expression;
    if(Parse_factor(&p, pValue)) {
        // 解析が終了した文字列の位置を記録
        p = Skip_parce(p);
        if(end) { *end = p; }
        return 1;
    }
    return 0;
}

/* 計算式の操作 */
int Calc_operation(int argc, char *argv[])
{
    char lop[ORDER]; // 左オペランド
    char rop[ORDER]; // 右オペランド
    
    memset(lop,0,sizeof(char)*ORDER);
    memset(rop,0,sizeof(char)*ORDER);
    
    const char *p; // 計算式を格納するポインタ
    char op; // 演算子
    char st[STRING_BUFFER_SIZE]; // コマンドライン引数を格納

    // パラメータのチェック
    if(argc <= 1 || argc >=5) return ERROR_CODE_NUMBER_OF_UNUSUAL_ARGS;
    
    if(!Storage(argc, argv, st)) return ERROR_CODE_STRING_BUFFER_OVER;
    
    printf("%s = \n", st);// 式を表示
    
    // stの解析
    if(Parse(st, &p, lop)) {
        op = *p; // opに演算子を代入
        // 第一引数が数値or文字だけの場合
        if(op == '\0') return ERROR_CODE_INVALID_EXPRESSION;
        // pの解析
        if(Parse(p+1, &p, rop)) {
            // 後ろに余計な文字がある
            if(*p != '\0') return ERROR_CODE_INVALID_EXPRESSION;
        }
    }
    
    short llop[N],lrop[N],lresult[N];
    memset(llop,0,sizeof(short)*N);
    memset(lrop,0,sizeof(short)*N);
    memset(lresult,0,sizeof(short)*N);

    switch(op) {
    case '+': case '-':
        atolb(lop,llop); print(llop);
        atolb(rop,lrop); print(lrop);
        if(op == '+') ladd(llop, lrop, lresult);
        else lsub(llop, lrop, lresult);
        break;
    case '*': case '/':
        atolb(lop,llop); print(llop);
        int irop = atoi(rop);
        if(op == '*') lmul(llop, irop, lresult);
        else ldiv(llop, irop, lresult);
        break;
    default: return ERROR_CODE_INVALID_OPERATOR;
    }
    print(lresult);
        
    return 0;
}

LONGBYTE Add(LONGBYTE lop, LONGBYTE rop) { return lop + rop; }
LONGBYTE Sub(LONGBYTE lop, LONGBYTE rop) { return lop - rop; }
LONGBYTE Mul(LONGBYTE lop, LONGBYTE rop) { return lop * rop; }
LONGBYTE Did(LONGBYTE lop, LONGBYTE rop) { return lop / rop; }
LONGBYTE Mod(LONGBYTE lop, LONGBYTE rop) { return lop % rop; }

void ladd(short* a, short* b, short* c)
{
    short cy=0;
    for(int i=N-1; i>=0; i--){
        c[i] = a[i]+b[i]+cy;
        if(c[i]<10000) cy=0;
        else { c[i] = c[i]-10000; cy = 1; }
    }
}

void lsub(short* a, short* b, short* c)
{
    short brrw=0;
    for(int i=N-1; i>=0; i--){
        c[i] = a[i]-b[i]-brrw;
        if(c[i]>0) brrw=0;
        else { c[i] = c[i]+10000; brrw = 1; }
    }
}

void lmul(short* a, short b, short* c)
{
    long d,cy=0;
    for(int i=N-1; i>=0; i--){
        d = a[i]; c[i] = (d*b+cy)%10000;
        cy = (d*b+cy)/10000;
    }
}

void ldiv(short* a, short b, short* c)
{
    long d,rem=0;
    for(int i=0; i<N; i++){
        d = a[i]; c[i] = (d+rem)/b;
        rem = ((d+rem)%b)*10000;
    }
}

実行結果
Gami[335]% ./list_91.exe "1234567890112 / 100"
1234567890112 / 100 = 
0000 0000 0000 0000 0000 0000 0001 2345 6789 0112 
0000 0000 0000 0000 0000 0000 0000 0123 4567 8901 
inserted by FC2 system