Dependents:   WeatherStation

ILinterpreter.cpp

Committer:
okini3939
Date:
2011-10-07
Revision:
3:ed09123d603f
Parent:
2:64bc38078592

File content as of revision 3:ed09123d603f:

/*
 * Instruction List interpreter library
 * Copyright (c) 2011 Hiroshi Suga
 * Released under the MIT License: http://mbed.org/license/mit
 */

/** @file
 * @brief Instruction List interpreter
 */

#include "mbed.h"
#include "ILinterpreter.h"

#undef DEBUG

struct MNE_str {
    eMNEMONIC mne;
    char str[5];
};

#define IL_MNE_NUM 22
static const struct MNE_str mne_str[IL_MNE_NUM] = {
    {MNE_DEF, "DEF"},
    {MNE_LD, "LD"}, {MNE_LDI, "LDI"}, {MNE_LDP, "LDP"}, {MNE_LDF, "LDF"},
    {MNE_OR, "OR"}, {MNE_ORI, "ORI"}, {MNE_ORP, "ORP"}, {MNE_ORF, "ORF"},
    {MNE_AND, "AND"}, {MNE_ANI, "ANI"}, {MNE_ANDP, "ANDP"}, {MNE_ANDF, "ANDF"},
    {MNE_ORB, "ORB"}, {MNE_ANB, "ANB"}, {MNE_INV, "INV"},
    {MNE_MPS, "MPS"}, {MNE_MRD, "MRD"}, {MNE_MPP, "MPP"},
    {MNE_OUT, "OUT"}, {MNE_SET, "SET"}, {MNE_RST, "RST"},
};

struct EXP_str {
    eEXPRESSION exp;
    char str[3];
};

#define IL_EXP_NUM 10
static const struct EXP_str exp_str[IL_EXP_NUM] = {
    {EXP_EQ, "=="}, {EXP_EQ, "="}, {EXP_NE, "!="}, {EXP_NE, "<>"},
    {EXP_LT, "<="}, {EXP_LE, "<"}, {EXP_GT, ">"}, {EXP_GE, ">="},
    {EXP_MOD, "%"}, {EXP_NMOD, "!%"},
};


ILinterpreter::ILinterpreter () {
    il_count = 0;
    memset(&inout, 0, sizeof(inout));
    inout.sec = time(NULL) + (60 * 60 * 9);
    inout_old = inout;
    cb_input = NULL;
    cb_output = NULL;
}

// input relay, expression
int ILinterpreter::input (tInOut *io, int i, int old) {
    int keynum;
    float value, check;
    struct tm *tim;

    tim = localtime(&io->sec);
    keynum = il[i].keynum;
    // right value
    check = il[i].value;

    // left value
    value = 0;
    switch (il[i].key) {

    case 'y':
        value = tim->tm_year + 1900;
        break;
    case 'm':
        value = tim->tm_mon + 1;
        break;
    case 'd':
        value = tim->tm_mday;
        break;
    case 'h':
        value = tim->tm_hour;
        break;
    case 'i':
        value = tim->tm_min;
        break;
    case 's':
        value = tim->tm_sec;
        break;

    case '0':
        value = 0;
        break;
    case '1':
        value = 1;
        break;

    case 'M': // RELAY
        if (keynum >= IL_RELAY_NUM) break;
        value = io->relay[keynum];
        break;

    case 'T': // Timer
        if (keynum >= IL_TIMER_NUM) break;
        if (il[i].expression == EXP_NULL) {
            value = io->timer_flg[keynum] && io->timer_set[keynum] && io->timer_cnt[keynum] >= io->timer_set[keynum];
        } else {
            value = (float)io->timer_cnt[keynum] / 10.0;
        }
        break;

    case 'C': // Counter
        if (keynum >= IL_COUNTER_NUM) break;
        if (il[i].expression == EXP_NULL) {
             value = io->count_cnt[keynum] >= io->count_set[keynum];
        } else {
             value = io->count_cnt[keynum];
        }
        break;

    default: // order input
        if (cb_input) {
            value = (*cb_input)(il[i].key, keynum, il[i].expression, old);
        }
        break;
    }

    // expression
    switch (il[i].expression) {
    case EXP_EQ:
        return value == check;
    case EXP_NE:
        return value != check;
    case EXP_LE:
        return value <= check;
    case EXP_LT:
        return value < check;
    case EXP_GE:
        return value >= check;
    case EXP_GT:
        return value > check;
    case EXP_MOD:
        return (int)value % (int)check;
    case EXP_NMOD:
        return ! ((int)value % (int)check);
    }

    return value != 0;
}

// output relay
void ILinterpreter::output (int i, int reg, eMNEMONIC mne) {
    int keynum;

    keynum = il[i].keynum;
#ifdef DEBUG
    printf("output [%c%d] reg=%d sr=%d\r\n", il[i].key, keynum, reg, mne);
#endif

    switch (il[i].key) {
    case 'M': // relay
        if (keynum >= IL_RELAY_NUM) break;
        if (mne == MNE_OUT) {
            inout.relay[keynum] = reg;
        } else
        if (mne == MNE_SET && reg) {
            inout.relay[keynum] = 1;
        } else
        if (mne == MNE_RST && reg) {
            inout.relay[keynum] = 0;
        }
        break;

    case 'T': // Timer
        if (keynum >= IL_TIMER_NUM) break;
        if (mne == MNE_OUT) {
            if (! inout.timer_flg[keynum]) {
                // set timer
                inout.timer_cnt[keynum] = 0;
            }
            inout.timer_flg[keynum] = reg;
        } else
        if (mne == MNE_RST && reg) {
            inout.timer_cnt[keynum] = 0;
        }
        break;

    case 'C': // Counter
        if (keynum >= IL_COUNTER_NUM) break;
        if (mne == MNE_OUT && reg) {
            if (inout.count_rev[keynum]) {
                inout.count_cnt[keynum] --;
            } else {
                inout.count_cnt[keynum] ++;
            }
        } else
        if (mne == MNE_RST && reg) {
            inout.count_cnt[keynum] = 0;
        }
    case 'R': // Counter (reverse)
        if (keynum >= IL_COUNTER_NUM) break;
        if (mne == MNE_OUT) {
            inout.count_rev[keynum] = reg;
        }
        break;

    default: // order output
        if (cb_output) {
            (*cb_output)(il[i].key, keynum, reg, mne);
        }
        break;
    }
}

// execute IL
int ILinterpreter::exec () {
    int i, j, reg = -1;
    tInOut inout_tmp;

    if (! il_count) return 0;

    addr = 0;
    inout.sec = time(NULL);
    inout_tmp = inout;
#ifdef DEBUG
    printf("timer0=%d(%d) timer1=%d(%d)\r\n", inout.timer_cnt[0], inout.timer_set[0], inout.timer_cnt[1], inout.timer_set[1]);
#endif

    // mnemonic decode
    for(i = 0; i < il_count; i ++) {
        switch (il[i].mnemonic) {
        case MNE_LD:
            push(reg);
            reg = input(&inout, i);
            break;
        case MNE_LDI:
            push(reg);
            reg = ! input(&inout, i);
            break;
        case MNE_LDP:
            push(reg);
            reg = input(&inout, i) && ! input(&inout_old, i, 1);
            break;
        case MNE_LDF:
            push(reg);
            reg = ! input(&inout, i) && input(&inout_old, i, 1);
            break;

        case MNE_AND:
            reg = reg && input(&inout, i);
            break;
        case MNE_ANI:
            reg = reg && ! input(&inout, i);
            break;
        case MNE_ANDP:
            reg = reg && (input(&inout, i) && ! input(&inout_old, i, 1));
            break;
        case MNE_ANDF:
            reg = reg && (! input(&inout, i) && input(&inout_old, i, 1));
            break;

        case MNE_OR:
            reg = reg || input(&inout, i);
            break;
        case MNE_ORI:
            reg = reg || ! input(&inout, i);
            break;
        case MNE_ORP:
            reg = reg || (input(&inout, i) && ! input(&inout_old, i, 1));
            break;
        case MNE_ORF:
            reg = reg || (! input(&inout, i) && input(&inout_old, i, 1));
            break;

        case MNE_ANB:
            if (pop(&j) || j == -1) return -1;
            reg = reg && j;
            break;
        case MNE_ORB:
            if (pop(&j) || j == -1) return -1;
            reg = reg || j;
            break;

        case MNE_INV:
            reg = ! reg;
            break;

        case MNE_MPS:
            if (push(reg)) return -1;
            break;
        case MNE_MRD:
            if (read(&reg) || reg == -1) return -1;
            break;
        case MNE_MPP:
            if (pop(&reg) || reg == -1) return -1;
            break;

        case MNE_OUT:
        case MNE_SET:
        case MNE_RST:
            output(i, reg, il[i].mnemonic);
            break;
        }
    }

    inout_old = inout_tmp;

    return 0;
}

// set callback function
struct tInOut* ILinterpreter::attach (float (*pf_i)(char, int, eEXPRESSION, int), void (*pf_o)(char, int, int, eMNEMONIC)) {
    cb_input = pf_i;
    cb_output = pf_o;
    return &inout;
}

// timer 10Hz
void ILinterpreter::pool () {
    int i;

    if (! il_count) return;

    // timer
    for (i = 0; i < IL_TIMER_NUM; i ++) {
        if (inout.timer_flg[i] && inout.timer_cnt[i] < inout.timer_set[i]) {
            inout.timer_cnt[i] ++;
        }
    }
}

// load sub
void ILinterpreter::load_exp (int i, char *buf) {
    int j, len;
    char *tmp;

    // MNEMONIC "KEY""num"==value
    il[i].key = buf[0];
    il[i].keynum = strtol(&buf[1], &tmp, 10);
    il[i].expression = EXP_NULL;
    il[i].value = 0;

    if (tmp) {
        // expression
        for (j = 0; j < IL_EXP_NUM; j ++) {
            len = strlen(exp_str[j].str);
            if (strncmp(tmp, exp_str[j].str, len) == 0 && tmp[len] >= '0' && tmp[len] <= '9') {
                // MNEMONIC KEYnum"==""value"
                il[i].expression = exp_str[j].exp;
                il[i].value = atof(&tmp[len]);
                break;
            }
        }
    }
}

// load IL file
int ILinterpreter::load (char *file) {
    FILE *fp;
    char c;
    int i, j, len;
    char buf[20];

    il_count = 0;

    fp = fopen(file, "r");
    if (fp == NULL) return -1;

    i = 0;
    for (;;) {
        if (il_count >= IL_NUM) break;
        c = fgetc(fp);
        if (feof(fp)) break;

        if (c != '\r' && c != '\n' && i < 40 - 1) {
            // load
            buf[i] = c;
            i ++;
            continue;
        }
        buf[i] = 0;
        
        if (i == 0 || buf[0] == '#' || buf[0] == ';') {
            // comment
            i = 0;
            continue;
        }

        // mnemonic
        for (j = 0; j < IL_MNE_NUM; j ++) {
            len = strlen(mne_str[j].str);
            if (strncmp(buf, mne_str[j].str, len) == 0 && (buf[len] == ' ' || buf[len] == 0)) {
                // "MNEMONIC" KEYnum==value
                il[il_count].mnemonic = mne_str[j].mne;
                load_exp(il_count, &buf[len + 1]);
#ifdef DEBUG
                printf("%d: M=%d [%c%d] E=%d V=%f\r\n", il_count, il[il_count].mnemonic, il[il_count].key, il[il_count].keynum, il[il_count].expression, il[il_count].value);
#endif
                il_count ++;
                break;
            }
        }
        if (strncmp(buf, "END", 3) == 0) break;
        if (j == IL_MNE_NUM) return -1;

        i = 0;
    }

    // init
    for (i = 0; i < il_count; i ++) {
      if (il[i].mnemonic == MNE_DEF) {
        switch (il[i].key) {
        case 'T': // Timer
            inout.timer_set[il[i].keynum] = (int)il[i].value * 10;
            break;

        case 'C': // Counter
            inout.count_set[il[i].keynum] = (int)il[i].value;
            break;
        }
      }
    }

    fclose(fp);

    return il_count;
}

int ILinterpreter::push (int dat) {

    if (addr >= IL_STACK) {
        return -1;
    }
    stack[addr] = dat;
    addr ++;
    return dat;
}

int ILinterpreter::pop (int *dat) {

    if (addr == 0) {
        return -1;
    }
    addr --;
    *dat = stack[addr];
    return 0;
}

int ILinterpreter::read (int *dat) {

    if (addr == 0) {
        return -1;
    }
    *dat = stack[addr];
    return 0;
}