Last Update: Mar.22,2002

C Source Library

「LSI C-86 Ver.3.30c 試食版」、「Borland C++ 5.5」、「Microsoft Visual C++ 6.0」でコンパイル出来ます。

■ 四則演算インタプリタ

/*
 *  interp.c : 四則演算インタプリタ
 *
 *      Copyright (c) 2001, 2002 AOK. 
 *  
 *      2001/10/26 - 初版
 *      2002/03/22 - 2版
 *
 *  再帰下降解析を使った簡単なインタプリタです。加減乗除
 *  [+,-,*,/]と括弧[(,)]と正負符号(+,-)が使えます。
 *
 *      例: 7*6+5*(8-4)/2+1 【=53】
 *
 */

#include <stdio.h>
#include <stdlib.h>

#define isspace(x)  ((x==' ')||(x=='\t'))
#define isdigit(x)  ((x>='0')&&(x<='9'))
#define isop(x)     ((x=='+')||(x=='-')||(x=='*')||(x=='/')||(x=='(')||(x==')')) 

char buf[127], sym;
int num, pc, err;

int addsub(void);

/* デバグ用 */
void debug(const char *s)
{
    printf("* %-11s sym=%c num=%d\n", s, sym, num);
}

/* エラー表示 */
void error(const char *s)
{
    fprintf(stderr, "[%02d:%c] %s\n", pc, sym, s);
    sym = '?';
    err++;
}

/* 1文字を得る */
void getnext(void)
{
    sym = buf[pc++];
    if (!isdigit(sym) && !isop(sym) && sym !='\0' && !isspace(sym))
        error("不正な文字");
}

/* シンボルの種類の判定 */
void getsym(void)
{
    sym = ' ';
    while (isspace(sym)) getnext();
    if (isdigit(sym)) {
        num = 0;
        while (isdigit(sym)) {
            num = num * 10 + sym - '0';
            getnext();  
        }
        sym = '@';
        pc--;
    }
}

/* 因子 */
int factor(void)
{
    int n;
    debug("factor in");
    if (sym == '(') {
        getsym();
        n = addsub();
        if (sym != ')') error("')'がありません");
        getsym();
    } else if (sym == '@') {
        n = num;
        getsym();
    } else {
        error("式が正しくありません");
    }
    debug("factor out");
    return n;
}

/* 乗除算 */
int muldiv(void)
{
    int m, n;
    debug("muldiv in");
    n = factor();
    while (sym == '*' || sym == '/') {
        if (sym == '*') {
            getsym();
            n *= factor();
        } else if (sym == '/') {
            getsym();
            if ((m = factor()) != 0)
                n /= m;
            else {
                error("ゼロで除算できません");
                break;
            }
        }
    }
    debug("muldiv out");
    return n;
}

/* 加減算 */
int addsub(void)
{
    int n;
    debug("addsub in");
    if (sym == '+') {
        getsym();
        n = muldiv();
    } else if (sym == '-') {
        getsym();
        n = -muldiv();
    } else {
        n = muldiv();
    }
    while (sym == '+' || sym == '-') {
        if (sym == '+') {
            getsym();
            n += muldiv();
        } else if (sym == '-') {
            getsym();
            n -= muldiv();
        }
    }
    debug("addsub out");
    return n;
}

/* メインルーチン */
int main(void)
{
    int r;
    for (;;) {
        buf[0] = '\0';
        num = pc = err = 0;
        putchar('>');
        gets(buf);
        if (buf[0]=='\0') break;
        getsym();
        r = addsub();
        if (sym != '\0') /* 式を最後まで評価したかのチェック */
            error("式が正しくありません");
        if (err) fprintf(stderr, "%d個のエラーが発生\n", err);
        else printf("%s=%d\n", buf, r);
    }
    return 0;
}