トップJavaScript > 電卓

電卓

BNF記法の事例として書いたプログラムである。




本来の四則演算の構文規則(BNF記法)は

    <addsub> ::= <addsub> + <muldiv> | <addsub> - <muldiv> | <muldiv>  
    <muldiv> ::= <muldiv> * <factor> | <muldiv> / <factor> | <factor>
    <factor> ::= 数値 | ( <addsub> )
であるが、これでは再帰プログラムが書けないので、次のように書き換える。
    <addsub> ::= <muldiv> { + <muldiv> | - <muldiv> } 
    <muldiv> ::= <factor> { * <factor> | / <factor> } 
    <factor> ::= 数値 | ( <addsub> )

プログラム・ソースを以下に示す。

calc01.js
var input = "";
var items = new Array();
var nItem = 0;
var ix = 0;
var num = "";

function push(c) {
    if (c == 'C') {
        input = "";
        items = new Array();
        nItem = 0;
        ix = 0;
        num = "";
    } else if (c.match(/\d|\./)) {
        num += c;
        input += c;
    } else if (c == '=') {
        if (num.length > 0) {
            items[nItem++] = num;
            num = "";
        }
        input += "=" + calc(items);
    } else if (c != '') {
        if (num.length > 0) {
            items[nItem++] = num;
            num = "";
        }
        items[nItem++] = c;
        input += c;
    }
    document.getElementById('in').value = input;
}

function array(id) {
    var labels = [ 
         ["0", "1", "2", "+", "("],
         ["3", "4", "5", "-", ")"],
         ["6", "7", "8", "*", ""],
         ["9", ".", "C", "/", "="] ];

    var buttons = "<table border='0'>";
    for (var i = 0; i < labels.length; i++) {
        buttons += "<tr>";
        for (var j = 0; j < labels[i].length; j++) {
            buttons += "<td><input type='button' value='" + labels[i][j]
                     + "' onclick=push('" + labels[i][j] + "')></td>";
        }
        buttons += "</tr>";
    }
    buttons += "</table>";
    document.getElementById(id).innerHTML = buttons;
    input = "";
}

function calc(){
    return addsub();
}

function addsub(){
    var val = muldiv();
    while (ix < items.length && items[ix].match(/[\+-]/)) {
        val = ("+" == items[ix++]) ? (val + muldiv()) : (val - muldiv());
    }
    return val;
}

function muldiv(){
    var val = factor();
    while (ix < items.length && items[ix].match(/[\*/]/)) {
        var op = items[ix++];
        val = ("*" == op) ? (val * factor()) : (val / factor());
    }
    return val;
}

function factor(){
    var val;
    if ("(" == items[ix]){
        ix++;
        val = addsub();
        if (")" != (items[ix])) alert(")がありません!");
        ix++;    // ポインタを ) の次へ進める
    } else {
        val = parseFloat(items[ix++]);
    } 
    return val;
}