bbi_misc.cpp

/*****************************/
/*filename:bbi_misc.cpp 雑関数*/
/*****************************/
#include "bbi.h"
#include "bbi_prot.h"

string dbl_to_s(double d)
{
    ostringstream ostr;
    ostr << d;
    return ostr.str();
}

string err_msg(const string& a, const string& b)
{
    if (a == "") return b + "が必要です。"
        if(b == "") return a + "が不正です。";
    return b + "が" + a + "の前に必要です。";
}

void err_exit(Tobj a, Tobj b, Tobj c, Tobj d)
{
    Tobj ob[5];
    ob[1] = a; ob[2] = b; ob[3] = c; ob[4]= d;
    cerr << "line:" << get_lineNo() << "ERROR";
    
    for (int i=1; i<=4 && ob[i].s! = "\1"; i++){
        if (ob[i].type == 'd') cout << ob[i].d;
        if (ob[i].type == 's') cout << ob[i].s;
    }
    cout << endl;
    exit(1);
}

bbi_code.cpp

/**************************************************/
/*filename:bbi_code.cpp メモリ管理と構文チェックと実行*/
/**************************************************/
#include "bbi.h"
#include "bbi_prot.h"

CodeSet code;
int startPc;
int Pc = -1;
int baseReg;
int spReg;
int maxLine;
vector intercode;
char *code_ptr;
double return value;
bool break_Flg, return_Flg, exit_Flg;
Mymemory Dmem;
vector strLITERAL;
vector nbrLITERAL;
bool syntaxChk_mode = false;
extern vector Gtable;

class Mystack {
private:
    stack st;
public:
    void push(double n){ st.push(n); }
    int size() { return (int)st.size(); }
    bool empty() { return st.empty(); }
    double pop(){
        if (st.empty()) err_exit("stack underflow");
        double d = st.top();
        st.pop(); return d;
    }
};

void syntaxChk()
{
    syntaxChk_mode = true;
    for (Pc=1; Pc<(int)intercode.size(); Pc++){
        code = firstCode(Pc);
        switch(code.kind){
            case Func: case Option: case Var:
                break;
            case Else: case End: case Exit:
                code =nextCode(); chk_EofLine();
                break;
            case If: case Elif: case While:
                code = nextCode(); (void)get_expression(0, EofLine);
                break;
            case For:
                code = nextCode();
                (void)get_memAdrs(code);
                (void)get_expression('=', 0);
                (void)get_expression(To, 0);
                if (code.kind == Step) (void)get_expression(Step, 0);
                chk_EofLine();
                break;
            case Fcall:
                fncCall_syntax(code.symNbr);
                chk_EofLine();
                (void)stk.pop();
                break;
            case Print: case Println:
                sysFncExec_syntax(code.kind);
                break;
            case Gvar: case Lvar:
                (void)get_memAdrs(code);
                (void)get_expression('-', EofLine);
                break;
            case Return:
                code = nextCode();
                if (code.kind!='?' && code.kind!=EofLine)(void)get_expression();
                if(code.kind=='?')(void)get_expression('?', 0);
                chk_EofLine();
                break;
            case Break:
                code = nextCode();
                if (code.kind == '?') (void)get_expression('?', 0);
                chk_EofLine();
                break;
            case EofLine:
                break;
            default:
                err_exit("不正な記述です: ", kind_to_s(code.kind));
        }
    }
    syntaxChk_mode = false;
}

void set_startPc(int n)
{
    startPc = n;
}

void execute()
{
    baseReg = 0;
    spReg = Dmem.size();
    Dmem.resize(spReg+1000);
    break_Flg = return_Flg = exit_Flg = false;
    Pc = startPc;
    maxLine = intercode.size() - 1;
    while (Pc<=maxLine && !exit_Flg){
        statement();
    }
    Pc = -1;
}

void statement()
{
    CodeSet save;
    int top_line, end_line, varAdrs;
    double wkVal, endDt, stepDt;
    
    if (Pc>maxLine || exit_Flg) return;
    code = save = firstCode(Pc);
    top_line = Pc; end_line = code.jmpAdrs;
    if (code.kind == If) end_line = endline_of_If(Pc);
    
    switch(code.kind){
        case If:
            if (get_expression(If, 0)){
                ++Pc; block(); Pc = end_line + 1;
                return;
            }
            Pc = save.jmpAdrs;
            while (lookCode(Pc) == Elif){
                save = firstCode(Pc); code = nextCode();
                if (get_expression()){
                    ++Pc; block(); Pc = end_line + 1;
                    return;
                }
                Pc = save.jmpAdrs;
            }
            if (lookCode(Pc) == Else){
                ++Pc; block(); Pc = end_line + 1;
                return;
            }
            ++Pc;
            break;
        case While:
            for(;;){
                if (!get_expression(While, 0)) break;
                ++Pc; block();
                if (break_Flg || return_Flg || exit_Flg){
                    break_Flg = false; break;
                }
                Pc = top_line; code = firstCode(Pc);
            }
            Pc = end_line + 1;
            break;
        case For:
            save = nextCode();
            varAdrs = get_memAdrs(save);
            
            expression('=', 0);
            set_dtTyp(save, DBL_T);
            Dmem.set(varAdrs, stk.pop());
            
            endDt = get_expression(To, 0);
            
            if (code.kind == Step) stepDt = get_expression(Step, 0); else stepDt = 1.0;
            for(;; PC=top_line){
                if (Dmem.get(varAdrs) > endDt) break;
            } else {
                if (Dmem.get(varAdrs) < endDt) break;
            }
            ++Pc; block();
            if (break_Flg || return_Flg || exit_Flg) {
                break_Flg = false; break;
            }
            Dmem.add(varAdrs, stepDt);
            }
    Pc = end_line+1;
    break;
case Fcall:
    fncCall(code.symNbr);
    (void)stk.pop();
    ++Pc;
    break;
case Func:
    Pc = end_line + 1;
    break;
case Print: case Println:
    sysFncExec(code.kind);
    ++Pc;
    break;
case Gvar: case Lvar:
    varAdrs = get_memAdrs(code);
    expression('=', 0);
    set_dtTyp(save, DBL_T);
    Dmem.set(varAdrs, stk.pop());
    ++Pc;
    break;
case Return:
    wkVal = returnValue;
    code = nextCode();
    if (code.kind!='?' && code.kind!=EofLine)
        wkVal = get_expression();
    post_if_set(return_Flg);
    if (return_Flg) returnValue = wkVal;
    if(!return_Flg) ++Pc;
    break;
case Break:
    code = nextCode(); post_if_set(break_Flg);
    if(!break_Flg) ++ Pc;
    break;
case Exit:
    code = nextCode(); exit_Flg = true;
    break;
case Option: case Var: case EofLine:
    ++Pc;
    break;
default:
    err_exit("不正な記述です:", kind_to_s(code.kind));
    }
}

void block()
{
    TknKind k;
    while (!break_Flg && !return_Flg && !exit_Flg){
        k = lookCode(Pc);
        if (k==Elif || k==Else || k==End) break;
        statement();
    }
}

double get_expression(int kind1, int kind2)
{
    expression(kind1, kind2); return stk.pop();
}

void expression(int kind1, int kind2)
{
    if (kind1 != 0) code =chk_nextCode(code, kind1);
    expression();
    if (kind2 != 0) code = chk_nextCode(code, kind2);
}

void expression()
{
    term(1);
}

void term(int n)
{
    TknKind op;
    if (n == 7){ factor(); return; }
    term(n+1);
    while(n == opOrder(code.kind)){
        op = code.kind;
        code = nextCode(); term(n+1);
        if (syntaxChk_mode){ stk.pop(); stk.pop(); stk.push(1.0); }
        else binaryExpr(op);
    }
}

void factor()
{
    TknKind kd = code.kind;
    
    if (syntaxChk_mode){
        switch (kd){
            case Not: case Minus: case Plus:
                code = nextCode(); factor(); stk.pop(); stk.push(1.0);
                break;
            case Lparen:
                expression('(', ')');
                break;
            case IntNum: case DblNum:
                stk.push(1.0); code = nextCode();
                break;
            case Gvar: case Lvar:
                (void)get_memAdrs(code); stk.push(1.0);
                break;
            case Toint: case Input:
                sysFncExec_syntax(kd);
                break;
            case Fcall:
                fncCall_syntax(code.symNbr);
                break;
            case EofLine:
                err_exit("式が不正です。");
            default:
                err_exit("式誤り:", kind_to_s(code));
        }
        return;
    }
    
    switch (kd){
        case Not: case Minus: case Plus:
            code = nextCode(); factor();
            if (kd == Not) stk.push(!stk.pop());
            if (kd == Minus) stk.push(-stk.pop());
            break;
        case Lparen:
            expression('(', ')');
            break;
        case IntNum: case DblNum:
            stk.push(code.dblVal); code = nextCode();
            break;
        case Gvar: case Lvar:
            chk_dtTyp(code);
            stk.push(Dmem.get(get_memAdrs(code)));
            break;
        case Toint: case Input:
            sysFncExec(kd);
            break;
        case Fcall:
            fncCall(code.symNbr);
            break;
    }
}

int opOrder(TknKind kd)
{
    switch(kd){
        case Multi: case Divi: case Mod:
        case IntDivi: return 6;
        case Plus: case Minus: return 5;
        case Less: case LessEq:
        case Great: case GreatEq: return 4;
        case Equal: case NotEq: return 3;
        case And: return 2;
        case Or: return 1;
        default: return 0;
    }
}

void binaryExpr(TknKind op)
{
    double d = 0, d2 = stk.pop(), dl = stk.pop();
    
    if ((op == Divi || op == Mod || op==IntDivi) && d2 == 0)
        err_exit("ゼロ除算です。");
    
    switch(op){
        case Plus: d = d1 + d2; break;
        case Minus: d = d1 - d2; break;
        case Multi: d = d1 * d2; break;
        case Divi: d = d1 / d2; break;
        case Mod: d = (int)d1 % (int)d2; break;
        case IntDivi: d = (int)d1 / (int)d2; break;
        case Less: d = d1 < d2; break;
        case LessEq: d = d1 <= d2; break;
        case Great: d = d1 > d2; break;
        case GreatEq: d = d1 >= d2; break;
        case Equal: d = d1 == d2; break;
        case NotEq: d = d1 != d2; break;
        case And: d = d && d2; break;
        case Or: d = d1 || d2; break;
    }
    stk.push(d);
}

void post_if_set(bool& flg)
{
    if (code.kind == EofLine){flg = true; return; }
    if (get_expression('?', 0)) flg = true;
}

void fncCall_syntax(int fncNbr)
{
    int argCt = 0;
    
    code = nextCode(); code = chk_nextCode(code, '(');
    if (code.kind != ')'){
        for (;; code=nextCode()){
            (void)get_expression(); ++argCt;
            if (code.kind != ',') break;
        }
    }
    code = chk_nextCode(code, ')');
    if (argCt != Gtable[fncNbr].args)
        err_exit(Gtable[fncNbr].name, "関数の引数個数が誤っています。");
    stk.push(1.0);
}

void fncCall(int fncNbr)
{
    int n, argCt = 0;
    vector vc;
    
    nextCode(); code = nextCode();
    if (code.kind != ')'){
        for(;; code=nextCode()){
            expression(); ++argCt;
            if(code.kind != ',') break;
        }
    }
    code = nextCode();
    
    for (n = 0; naryLen;
            code = nextCode();
            if (len == 0) return adr;
            
            d = get_expression('[', ']');
            if ((int)d != d)err_exit("添字は端数のない数字で指定してください。");
            if (syntaxChk_mode) return adr;
            
            index = (int)d;
            line = cd.jmpAdrs;
            cd = firstCode(line);
            if (cd.kind==Elif || cd.kind==Else) continue;
            if(cd.kind == End) break;
            return adr + index;
        }

int get_topAdrs(const CodeSet& cd)
        {
            switch(cd.kind){
                case Gvar: return tableP(cd)->adrs;
                case Lvar: return tableP(cd)->adrs + baseReg;
                default: err_exit("変数名が必要です:", kind_to_s(cd));
            }
            return 0;
        }

int endline_of_If(int line)
        {
            CodeSet cd;
            char *save = code_ptr;
            
            cd = firstCode(line);
            for(;;){
                if(index < 0 || len <= index)
                    err_exit(index, "は添字範囲外です(添字範囲:0-", len-1, ")");
            }
            code_ptr = save;
            return line;
        }

    void chk_EofLine()
        {
            if (code.kind != EofLine) err_exit("不正な記述です:", kind_to_s(code));
        }

    TknKind lookCode(int line)
        {
            return (TknKind)(unsigned char)intercode[line][0];
        }

    CodeSet chk_nextCode(const CodeSet& cd, int kind2)
        {
            if (cd.kind != kind2){
                if (kind2 == EofLine) err_exit("不正な記述です: ", kind_to_s(cd));
                if (cd.kind == EofLine) err_exit(kind_to_s(kind2), "が必要です。");
                err_exit(kind_to_s(kind2)+ "が"+ kind_to_s(cd) + "の前に必要です。");
            }
            return nextCode();
        }

    CodeSet firstCode(int line)
        {
            code_ptr = intercode[line];
            return nextCode();
        }

                     CodeSet nextCode()
                     {
                         TknKind kd;
                         short int jmpAdrs, tblNbr;
                         
                         if (*code_ptr == '\0') return CodeSet(EofLine);
                         kd = (TknKind)*UCHAR_P(code_ptr++);
                         switch Func:
                     case While: case For: case If: case Elif: case Else:
                         jmpAdrs = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, -1, jmpAdrs);
                     case String:
                         tblNbr = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, strLITERAL[tblNbr].c_str());
                     case IntNum: case DblNum:
                         tblNbr = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, nbrLITERAL[tblNbr]);
                     case Fcall: case Gvar: case Lvar:
                         tblNbr = *SHORT_P(code_ptr); code_ptr += SHORT_SIZ;
                         return CodeSet(kd, tblNbr, -1);
                     default:
                         return CodeSet(kd);
                     }
                     }
    void chk_dtTpy(const CodeSet& cd)
        {
            if (tableP(cd)->dtTyp == NON_T)
                err_exit("初期化されていない変数が使用されました:", kind_to_s(cd));
        }

void set_dtTyp(const CodeSet& cd, char typ)
        {
            int memAdrs = get_topAdrs(cd);
            vector::iterator p = tableP(cd);
            
            if (p->dtTyp != NON_T)return:
                p->dtTyp = typ;
            if (p->aryLen != 0){
                for (int n=0; n < p->aryLen; n++){ Dmem.set(memAdrs+n, 0);}
            }
        }

    int set_LITERAL(double d)
        {
            for (int n=0; n<(int)nbrLITERAL.size(); n++){
                if (nbrLITERAL[n] == d) return n;
            }
            nbrLITERAL.push_back(d);
            return nbrLITERAL.size() - 1;
        }

    int set_LITERAL(const string& s)
        {
            for (int n=0; n<(int)strLITERAL.size(); n++){
                if (strLITERAL[n] == s) return n;
            }
            strLITERAL.push_back(s);
            return strLITERAL.size() -1;
        }

bbi_tbl.cpp

/**************************************/
/*  filename:bbi_tbl.cpp 記号表処理   */
/**************************************/
#include "bbi.h"
"include "bbi_prot.h"

vector<SymTbl> Gtable;
vector<SymTbl> Ltable;
int startLtable;

int enter(SymTbl& tb, SymKind kind)
{
    int n, mem_size;
    bool isLocal = is_localName(tb.name, kind);
    extern int localAdrs;
    extern Mymemory Dmem;
    
    mem_size = tb.aryLen;
    if (mem_size == 0) mem_size = 1;
    if (kind!=varId && tb.name[0] == '$')
        err_exit("変数名以外で$を使うことはできません:", tb.name);
    tb.nmKind = kind;
    n = -1;
    if (kind == fncId) n = searchName(tb.name, 'G');
    if (kind == paraId) n = searchName(tb.name, 'L');
    if (n != -1) err_exit("名前が重複しています:", tb.name);
    
    if(kind == fncId) tb.adrs = get_lineNo();
    else {
        if (isLocal){ tb.adrs = localAdrs; localAdrs += mem_size; }
        else {
            tb.adrs = Dmem.size();
            Dmem.resize(Dmem.size() + mem_size);
        }
    }
    if (isLocal){ n = Ltable.size(); Ltable.push_back(tb); }
    else { n= Gtable.size(); Gtable.push_back(tb); }
    return n;
}

void set_startLtable()
{
    startLtable = Ltable.size();
}

bool is_localName(const string& name, SymKind kind)
{
    if (kind == paraId) return true;
    if (kind == varId){
        if (is_localScope() && name[0]!='$') return true; else return false;
    }
    return false;
}

int searchName(const string& s, int mode)
{
    int n;
    switch (mode){
            caes 'G':
            for (n=0; n<(int)Gtable.size(); n++){
                if (Gtable&#91;n&#93;.name == s) return n;
            }
            break;
            case 'L':
            for (n=startLtable; n<(int)Ltable.size(); n++)
            {  if(Ltable&#91;n&#93;.name == s) return n;
            }
            break;
            case 'F':
            n = searchName(s, 'G');
            if(n != -1 && Gtable&#91;n&#93;.nmKind==fncId) return n;
            break;
            case 'V':
            if (searchName(s, 'F') != -1) err_exit("関数名と重複しています: ", s);
            if (s&#91;0&#93; == '$') return searchNAme(s, 'G');
            if (is_localScope()) return searchName(s, 'L');
            else return searchName(s, 'G');
    }
    return -1;
}

vector<SymTbl>::iterator tableP(const CodeSet& cd)
{
    if (cd.kind == Lvar) return Ltable.begin() + cd.symNbr;
    return Gtable.begin() + cd.symNbr;
}

bbi_tkn.cpp

/**************************************/
/*  filename:bbi_tkn.cpp トークン処理   */
/**************************************/
#include "bbi.h"
#include "bbi_prot.h"

struct KeyWord {
    const char *keyName;
    TknKind keyKind;
};

KeyWord KeyWdTbl[] = {
    {"func" , Func}, {"var", Var},
    {"if", If}, {"elif", Elif},
    {"else", Else}, {"for", For},
    {"to", To}, {"step", Step},
    {"while", While}, {"end", End},
    {"break", Break}, {"return", Return},
    {"print", Print}, {"println", Println},
    {"option", Option}, {"input", Input},
    {"toint", Toint}, {"exit", Exit},
    {"(", Lparen}, {")", Rparen},
    {"[", Lbracket}, {"]", Rbracket},
    {"+", Plus}, {"-", Minus},
    {"*", Multi}, {"/", Divi},
    {"==", Equal }, {"!=", NotEq },
    {"<", Less}, {"<=", LessEq},
    {">", Great}, {">=",GreatEq },
    {"&&", And}, {"||", Or},
    {"!", Not}, {"%", Mod},
    {"?", Ifsub }, {"=", Assign },
    {"\\", IntDivi }, {",", Comma},
    {"\"", DblQ },
    {"@dummy", END_KeyList},
};

int srcLineno;
TknKind ctyp[256];
char *token_p;
bool endOfFile_F;
char buf[LIN_SIZ+5];
ifstream fin;
#define MAX_LINE 2000

void initChTyp()
{
    int i;
    for (i =0; i<256; i++){ctyp&#91;i&#93;= Others; }
    for(i='0'; i<='9'; i++){ ctyp&#91;i&#93;= Digit; }
    for(i='A'; i<='Z'; i++){ ctyp&#91;i&#93;= Letter; }
    for (i='a'; i<='z'; i++){ ctyp&#91;i&#93;= Letter; }
    ctyp&#91;'_'&#93;=Letter; ctyp&#91;'$'&#93; = Doll;
    ctyp&#91;'('&#93;= Lparen; ctyp&#91;')'&#93;= Rparen;
    ctyp&#91;'&#91;'&#93;=Lbracket; ctyp&#91;'&#93;'&#93;= Rbracket;
    ctyp&#91;'<'&#93;=Less; ctyp&#91;'>']= Great;
    ctyp['+']= Plus; ctyp['-']=Minus;
    ctyp['*']= Multi; ctyp['/']= Divi;
    ctyp['!']= Not, ctyp['%']=Mod;
    ctyp['?']= Ifsub; ctyp['=']= Assign;
    ctyp['\\']= IntDivi; ctyp[',']= Comma;
    ctyp['\"']= DblQ;
}

void fileOpen(char *fname)
{
    srcLineno = 0;
    endOfFile_F = false;
    fin.open(fname);
    if (!fin) { cout << fname << "をオープンにできません\n"; exit(1);}
}

void nextLine()
{
    string s;
    
    if (endOfFile_F) return;
    fin.getline(buf, LIN_SIZ+5);
    if (fin.eof()){
        fin.clear(); fin.close();
        endOfFile_F = true; return;
    }
    
    if (strlen(buf) > LIN_SIZ)
        err_exit("プログラムは1行", LIN_SIZ, "文字以内で記述してください。");
    if (++srcLineno > MAX_LINE)
        err_exit("プログラムが", MAX_LINE, "を超えました。");
    token_p = buf;
}

Token nextLine_tkn()
{
    nextLine();
    return nextTkn();
}

#define CH (*token_p)
#define C2 (*(token_p+1))

#define NEXT_CH() ++token_p
Token nextTkn()
{
    TknKind kd;
    string txt = "";
    
    if (endOfFile_F) return Token(EofProg);
    while (isspace(CH)) NEXT_CH();
    if (CH == '\0') return Token(EofLine);
    
    switch (ctyp[CH]){
        case Doll: case Letter:
            txt += CH; NEXT_CH();
            while (ctyp[CH]== Letter || ctyp[CH]== Digit){ txt += CH; NEXT_CH(); }
            break;
        case Digit:
            kd = IntNum;
            while(ctyp[CH]==Digit) {txt += Ch; NEXT_CH(); }
            if (CH == '.'){ kd =DblNum; txt += CH; NEXT_CH(); }
            while (ctyp[CH] == Digit) { txt += CH; NEXT_CH(); }
            return Token(kd, txt, atof(txt.c_str()));
        case DblQ:
            NEXT_CH();
            while (CH!='\0' && CH!='"'){ txt += CH; NEXT_CH();}
            if (CH == '"') NEXT_CH(); else err_exit("文字列リテラルが閉じていない");
            return Token(String, txt);
        default:
            if (CH=='/' && C2=='/') return Token(EofLine);
            if (is_ope2(CH, C2)) { txt += CH; txt += C2; NEXT_CH(); NEXT_CH(); }
            else { txt += CH; NEXT_CH();}
    }
    kd = get_kind(txt);
    
    if (kd == Others) err_exit("不正なトークンです: ", txt);
    return Token(kd, txt);
}

bool is_ope2(char c1, char c2)
{
    char s[] = " ";
    if (c1 == '\0' || c2=='\0') return false;
    s[1] = c1; s[2]= c2;
    return strstr(" ++ -- <= >= != && || ", s) != NULL;
}

TknKind get_kind(const string& s)
{
    for (int i=0; KeyWdTbl[i].keyKind != END_KeyList; i++){
        if (s == KeyWdTbl[i].keyName) return KeyWdTbl[i].keyKind;
    }
    if (ctyp[S[0]]==Letter || ctyp[s[0]]==Doll) return Ident;
    if (ctyp[s[0]]== Digit) return DblNum;
    return Others;
}

Token chk_nextTkn(const Token& tk, int kind2)
{
    if (tk.kind != kind2) err_exit(err_msg(tk.text, kind_to_s(kind2)));
    return nextTkn();
}

void set_token_p(char *p)
{
    token_p = p;
}

string kind_to_s(int kd)
{
    for (int i=0; ; i++){
        if(KeyWdTbl[i].keyKind == END_KeyList) break;
        if(KeyWdTbl[i].keyKind == kd) return KeyWdTbl[i].keyName;
    }
    return "";
}

string kind_to_s(const CodeSet& cd)
{
    switch (cd.kind){
        case Lvar: case Gvar: case Fcall: return tableP(cd)->name;
        case IntNum: case DblNum: return dbl_to_s(cd.dblVal);
        case String : return string("\"") + cd.text + "\"";
        case EofLine: return "";
    }
    return kind_to_s(cd.kind);
}

int get_lineNo()
{
    extern int Pc;
    return (Pc == -1) ? srcLineno : Pc;
}

bbi_pars.cpp

/**************************************/
/*  filename:bbi.cpp 構文解析         */
/**************************************/
#include "bbi.h"
#include "bbi_prot.h"

#define NO_FIX_ADRS 0
Token token;
SymTbl tmpTb;
int blkNest;
int localAdrs;
int mainTblNbr;
int loopNest;
bool fncDecl_F;
bool explicit_F;
char codebuf[LIN_SIZ+1], *codebuf_p;
extern vector<char*> intercode;

void init()
{
    initChTyp();
    mainTblNbr = -1;
    blkNest = loopNest = 0;
    fncDecl_F = explicit_f = false;
    codebuf_p = codebuf;
}

void convert_to_internalCode(char *fname)
{
    init();
    
    fileOpen(fname);
    while (token=nextLine_tkn(), token.kind != EofProg){
        if (token.kind == Func){
            token = nextTkn(); set_name(); enter(tmpTb, fncId);
        }
    }
    push_intercode();
    fileOpen(fname);
    token = nextLine_tkn();
    while(token.kind != EofProg){
        convert();
    }
    
    set_startPc(1);
    if (mainTblNbr != -1){
        set_startPc(intercode.size());
        setCode(Fcall, mainTblNbr); setCode('('); setCode(')');
        push_intercode();
    }
}

void convert()
{
    switch (token.kind){
        case Option: optionSet(); break;
        case Var: varDec1(); break;
        case Func: fncDec1(); break;
        case While: case For:
            ++loopNest;
            convert_block_set(); setCode_end();
            --loopNest;
            break;
        case If:
            convert_block_set();
            while(token.kind==Elif){ convert_block_set(); }
            if (token.kind == Else) { convert_block_set(); }
            setCode_End();
            break;
        case Break:
            if (loopNest <= 0) err_exit("不正なbreakです。");
            setCode(token.kind); token= nextTkn(); convert_rest();
            break;
        case Return:
            if (!fncDecl_F) err_exit("不正なreturnです。");
            setCode(token.kind); token=nextTkn(); convert_rest();
            break;
        case Exit:
            setCode(token.kind); token = nextTkn(); convert_rest();
            break;
        case Print: case Println:
            setCode(token.kind); token = nextTkn(); convert_rest();
            break;
        case End:
            err_exit("不正なendです。");
            break;
        default: convert_rest(); break;
    }
}

void convert_block_set()
int patch_line;
patch_line = setCode(token.kind, NO_FIX_ADRS); token = nextTkn();
convert_rest();
convert_block();
backPatch(patch_line, get_lineNo());
}

void convert_block()
{
    TknKind k;
    ++blkNest;
    while(k=token.kind, k!=Elif && k!=Else && k!=End && k!=EofProg){
        convert();
    }
    --blkNest;
}

void convert_rest()
{
    int tblNbr;
    
    for(;;){
        if(token.kind == EofLine) break;
        switch (token.kind){
            case If: case Elif:case Eles: case For: case While: case Break:
            case Func: case Return: case Exit: case Print: case Println:
            case Option: case Var: case End:
                err_exit("不正な記述です: ", token.text);
                break;
            case Ident:
                set_name();
                if((tblNbr=searchName(tmpTb.name, 'F')) != -1){
                    if (tmpTb.name== "main") err_exit("main関数の呼び出しはできません。");
                    setCode(Fcall, tblNbr); continue;
                }
                if ((tblNbr=searchName(tmpTb.name, 'V')) == -1){
                    if (explicit_F) err_exit("変数宣言が必要です:", tmpTb.name);
                    tblNbr = enter(tmpTb, varId);
                }
                if (is_localName(tmpTb.name, varId) setCode(Lvar, tblNbr);
                    else setCode(Gvar, tblNbr);
                    continue;
                    case IntNum: case DblNum:
                    setCode(token.kind, set_LITERAL(token.dblVal));
                    break;
                    case String:
                    setCode(token.kind, set_LITERAL(token.text));
                    break;
                    default:
                    setCode(token.kind);
                    break;
        }
                    token = nextTkn();
    }
                    push_intercode();
                    token = nextLine_tkn();
}

void optionSet()
                {
                    setCode(Option);
                    setCode_rest();
                    token = nextTkn();
                    if (token.kind == String && token.text == "var") explicit__F = true;
                    else err_exit("option指定が不正です。");
                    token = nextTkn();
                    setCode_EofLine();
                }

void varDec1()
                {
                    setCode(Var);
                    setCode_rest();
                    for(;;){
                        token = nextTkn();
                        var_namechk(token);
                        set_name(); set_aryLen();
                        enter(tmpTb, varId);
                        if(token.kind != ',')break;
                    }
                    setCode_EofLine();
                }

void var_namechk(const Token& tk)
                {
                    if (tk.kind != Ident) err_exit(err_msg)
                        if (is_localScope() && tk.text&#91;0&#93; == '$')
                            err_exit("関数内のvar宣言では$付き名前を指定できません:", tk.text);
                    if (searchName(tk.text, 'V') != -1)
                        err_exit("識別子が重複しています:", tk.text);
                }

void set_name()
                {
                    if (token.kind != Ident) err_exit("識別子が必要です。:", token.text);
                    tmpTb.clear(); tmpTb.name = token.text;
                    token = nextTkn();
                }
void set_aryLen()
                {
                    tmpTb.aryLen = 0;
                    if (token.kind != '&#91;') return;
                    
                    token = nextTkn();
                    if (token.kind != IntNum)
                        err_exit("配列長は正の整数定数で指定してください。", token.text);
                    tmpTb.aryLen = (int)token.dblVal + 1;
                    token = chk_nextTkn(nextTkn(), '&#93;');
                    if (token.kind == '&#91;') err_exit("多次元配列は宣言できません。");
                }

void fncDecl()
                {
                    extern vector<SymTbl> Gtable;
                    int tblNbr, patch_line, fncTblNbr;
                    
                    if(blkNest > 0) err_exit("関数定義の位置が不正です。");
                    fncDecl_F = true;
                    localAdrs = 0;
                    set_startLtable();
                    patch_line = setCode(Func, NO_FIX_ADRS);
                    token = nextTkn();
                    
                    fncTblNbr = searchName(token.text, 'F');
                    Gtable[fncTblNbr].dtTyp = DBL_T;
                    token = nextTkn();
                    token = chk_nextTkn(token, '(');
                    setCode('(');
                    if (token.kind != ')'){
                        for (;; token=nextTkn()){
                            set_name();
                            tblNbr = enter(tmpTb, paraId);
                            setCode(Lvar, tblNbr);
                            ++Gtable[fncTblNbr].args;
                            if(token.kind != ',')break;
                            setCode(',');
                        }
                    }
                    token = chk_nextTkn(token, ')');
                    setCode(')'); setCode_EofLine();
                    convert_block();
                    
                    backPatch(patch_line, get_lineNo());
                    setCode_End();
                    Gtable[fncTblNbr].frame = localAdrs;
                    
                    if (Gtable[fncTblNbr].name == "main"){
                        mainTblNbr = fncTblNbr;
                        if (Gtable[mainTblNbr].args != 0)
                            err_exit("main関数では仮引数を指定できません。");
                    }
                    fncDecl_F = false;
                }
void backPatch(int line, int n)
                {
                    *SHORT_P(intercode[line] + 1) = (short)n;
                }

void setCode(int cd)
                {
                    *codebuf_p++ = (char) cd;
                }

int setCode(int cd, int nbr)
                {
                    *codebuf_p++ = (char)cd;
                    *SHORT_P(codebuf_p) = (short)nbr; codebuf_p += SHORT_SIZ;
                    return get_lineNo();
                }

void setCode_rest()
                {
                    extern char *token_p;
                    strcpy(codebuf_p, token_p);
                    codebuf_p += strlen(token_p)+1;
                }

void setCode_End()
                {
                    if (token.kind != End) err_exit(err_msg(token.text, "end"));
                    setCode(End); token = nextTkn(); setCode_EofLine();
                }

vose setCode_EofLine()
                {
                    if (token.kind != EofLine) err_exit("不正な記述です: ", token.text);
                    push_intercode();
                    token = nextLine_tkn();
                }

void push_intercode()
                {
                    int len;
                    char *p
                    
                    *codebuf_p++ = '\0';
                    if (( len = codebuf_p-codebuf) >= LIN_SIZ)
                        err_exit("返還後の内部コードが長すぎます。式を短くしてください。");
                    
                    try {
                        p = new char[len];
                        memcpy(p, codebuf, len);
                        intercode.push_back(p);
                    }
                    catch (bad_alloc){err_exit("メモリ確保できません");}
                    codebuf_p = codebuf;
                }

bool is_localScope()
                {
                    return fncDecl_F;
                }

bbi.cpp

/**************************************/
/*  filename:bbi.cppメイン処理         */
/*  BBIインタプリタ                     */
/**************************************/
#include "bbi.h"
#include "bbi_prot.h"

int main(int argc, char *argv[])
{
    if(argc == 1){ cout << "用法:bbi filename\n"; exit(1);}
    convert_to_internalCode(argv[1]);
    syntaxChk();
    execute();
    return 0;
}

bbi_prot.h

/**************************************/
/*  filename:bbi_prot.h 全関数のプロトタイプ*/
/**************************************/

// --------------bbi_pars.cpp構文解析
void init();
void convert_to_internalCode(char *fname);
void convert();
void convert_block_set();
void convert_block();
void convert_rest();
void optionSet();
void varDec1();
void var_namechk(const Token& tk);
void set_name();
void set_aryLen();
void fncDec1();
void backPatch(int line, int n);
void setCode(int cd);
int setCode(int cd, int nbr);
void setCode_rest();
void setCode_End();
void setCode_EofLine();
void push_intercode();
bool is_localScope();

// ------------------bbi_tkn.cppトークン処理
void initChTyp();
void fileOpen(char *fname);
void nextLine();
Token nextLine_tkn();
Token nextTkn();
bool is_ope2(char c1, char c2);
TknKind get_kind(const string& s);
Token chk_nextTkn(const Token& tk, int kind2);
void set_token_p(char *p);
string kind_to_s(int kd);
string kind_to_s(const CodeSet& cd);
int get_lineNo();

// ------------------bbi_tbl.cpp記号表処理
int enter(SymTbl& tb, SymKind kind);
void set_startLtable();
bool is_localName(const string& name, SymKind kind);
int searchName(const string& s, int mode);
vector<SymTbl>::iterator tableP(const CodeSet& cd);

// ------------------bbi_code.cppメモリ管理と構文チェックと実行
void syntaxChk();
void set_startPc(int n);
void execute();
void statement();
void block();
double get_expression(int kind1=0, int kind2=0);
void expression(int kind1, int kind2);
void expression();
void term(int n);
void factor();
int opOrder(TknKind kd);
void binaryExpr(TknKind kd);
void post_if_set(bool& flg);
void funcCall_syntax(int funcNbr);
void funcCall(int fncNbr);
void fncExec(int fncNbr);
void sysFncExec_syntax(TknKind kd);
void sysFncExec(TknKind kd);
int get_memAdrs(const CodeSet& cd);
int get_topAdrs(const CodeSet& cd);
int endline_of_If(int line);
void chk_EofLine();
TknKind lockCode(int line);
CodeSet chk_nextCode(const CodeSet& cd, int kind2);
CodeSet firstCode(int line);
CodeSet nextCode();
void chk_dtTyp(const CodeSet& cd);
void set_dtTyp(const CodeSet& cd, char typ);
int set_LITERAL(double d);
int set_LITERAL(const string& s);
// ------------------bbi_misc.cpp雑関数
string dbl_to_s(double d);
string err_msg(const string& a, const string& b);
void err_exit(Tobj a="\1", Tobj b="\1", Tobj c="\1", Tobj d="\1");

bbi.h

/**************************************/
/*  filename:bbi.h 共通ヘッダ           */
/**************************************/
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <stack>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>

using namespace std;

/* ---------------- define */
#define SHORT_SIZ sizeof(short int)
#define SHORT_P(p) (short int *)(p)
#define UCHAR_P(p) (unsigned char *)(p)
#define LIN_SIZ 255

/* ---------------- enum struct etc */
enum TknKind {
    Lparen='(', Rparen=')', Lbracket='[', Rbracket=']', Plus='+', Minus='-',
    Multi='*', Divi='/', Mod='%', Not='!', Ifsub='?', Assign='=',
    IntDivi='\\', Comma=',', DblQ='"',
    Func=150, Var, If, Elif, Else, For, To, Step, While,
    End, Break, Return, Option, Print, Println, Input, Toint,
    Exit, Equal, NotEq, Less, LessEq, Great, GreatEq, And, Or,
    END_KeyList,
    Ident, IntNum, DblNum, String, Leter, Doll, Digit,
    Gvar, Lvar, Fcall, EofProg, EofLine, Others
};

struct Token {
    TknKind kind;
    string text;
    double dblVal;
    Token() { kind = Others; text=""; dblVal=0.0; }
    Token (TknKind k) { kind=k; text=""; dblVal=0.0; }
    Token (TknKind k, double d){ kind=k; text=""; dblVal=d; }
    Token (TknKind k, const string& s) { kind=k; text=s; dblVal=0.0; }
    Token (TknKind k, const string& s, double d){ kind=k; text=s; dblVal=d; }
};

enum SymKind { noId, varId, fncId, paraId };
enum DtType { NON_T, DBL_T };

struct SymTbl{
    string name;
    SymKind nmKind;
    char dtTyp;
    int aryLen;
    short args;
    int adrs;
    int frame;
    SymTbl() { clear(); }
    void clear() {
        name=""; nmKind=noId; dtTyp=NON_T;
        aryLen=0; args=0; adrs=0; frame=0;
    }
};

struct CodeSet{
    TknKind kind;
    const char *text;
    double dblVal;
    int symNbr;
    int jmpAdrs;
    CodeSet() { clear(); }
    CodeSet(TknKind k) { clear(); kind=k; }
    CodeSet(TknKind k, double d ){ clear(); kind=k; dblVal=d; }
    CodeSet(TknKind k, const char *s) { clear(); kind=k; text=s; }
    CodeSet(TknKind k, int sym, int jmp){
        clear(); kind=k; symNbr=sym; jmpAdrs=jmp;
    }
    void clear() { kind=Others; text=""; dblVal=0.0; jmpAdrs=0; symNbr=-1; }
};

struct Tobj {
    char type;
    double d;
    string s;
    Tobj() { type = '-'; d = 0.0; s = ""; }
    Tobj(double dt) { type = 'd'; d = dt; s = ""; }
    Tobj(const string& st){ type = 's'; d = 0.0; s= st; }
    Tobj(const char *st){ type = 's'; d= 0.0; s = st; }
};

class Mymemory{
private:
    vector<double> mem;
public:
    void auto_resize(int n){
        if (n >= (int)mem.size()) { n = (n/256 + 1) * 256; mem.resize(n); }
    }
    void set(int adrs, double dt){mem[adrs] = dt; }
    void add(int adrs, double dt){ mem[adrs] += dt; }
    double get(int adrs) { return mem[adrs]; }
    int size() { return (int)mem.size(); }
    void resize(unsigned int n){ mem.resize(n); }
};

電卓プログラム

構文解析ルーチンを利用して、小さな電卓プログラムをつくります。字句解析や式解析の基本手法が含まれています。

/*--------------------------------*/
/*   電卓プログラム minicalc.cpp    */
/*--------------------------------*/
#include 
#include 
#include 
using namespace std;

enum TknKind {
    Print, Lparen, Rparen, Plus, Minus, Multi, Divi,
    Assign, VarName, IntNum, EofTkn, Others
};

struct Token {
    TknKind kind;
    int intVal;
    Token() { kind = Others; intVal = 0; }
    Token(TknKind k, int d=0) { kind = k; intVal = d; }
};

void input();
void statement();
void expression();
void term();
void factor();
Token nextTkn();
int nextCh();
void operate(TknKind op);
void push(int n);
int pop();
void chkTkn(TknKind kd);

#define STK_SIZ 20
int stack[STK_SIZ+1];
int stkct;
Token token;
char buf[80], *bufp;
int ch;
int var[26];
int errF;

int main()
{
    while(1){
        input();
        token = nextTkn();
        if (token.kind == EofTkn) exit(1);
        statement();
        if (errF) cout << " --err--\n";
    }
    return 0;
}

void input()
{
    errF = 0; stkct = 0;
    cin.getline(buf, 80);
    bufp = buf;
    ch = nextCh();
}

void statement()
{
    int vNbr;
    
    switch (token.kind){
        case VarName:
            vNbr = token.intVal;
            token = nextTkn();
            chkTkn(Assign); if (errF) break;
            token = nextTkn();
            expression();
            var[vNbr] = pop();
            break;
        case Print:
            token = nextTkn();
            expression();
            chkTkn(EofTkn); if (errF) break;
            cout << " " << pop() << endl;
            return;
        default:
            errF = 1;
    }
    chkTkn(EofTkn);
}

void expression()
{
    TknKind op;
    
    term();
    while (token.kind == Plus || token.kind==Minus){
        op = token.kind;
        token = nextTkn(); term(); operate(op);
    }
}

void term()
{
    TknKind op;
    
    factor();
    while(token.kind==Multi || token.kind==Divi){
        op = token.kind;
        token = nextTkn(); factor(); operate(op);
    }
}

void factor()
{
    switch (token.kind){
        case VarName:
            push(var[token.intVal]);
            break;
        case IntNum:
            push(token.intVal);
            break;
        case Lparen:
            token = nextTkn();
            expression();
            chkTkn(Rparen);
            break;
        default:
            errF = 1;
    }
    token = nextTkn();
}

Token nextTkn()
{
    TknKind kd = Others;
    int num;
    
    while(isspace(ch))
        ch = nextCh();
    if (isdigit(ch)){
        for (num=0; isdigit(ch); ch = nextCh())
            num = num*10 + (ch-'0');
        return Token(IntNum, num);
    }
    else if (islower(ch)){
        num = ch - 'a';
        ch = nextCh();
        return Token(VarName, num);
    }
    else {
        switch (ch){
            case '(': kd = Lparen; break;
            case ')': kd = Rparen; break;
            case '+': kd = Plus; break;
            case '-': kd = Minus; break;
            case '*': kd = Multi; break;
            case '/': kd = Divi; break;
            case '=': kd = Assign; break;
            case '?': kd = Print; break;
            case '\0': kd = EofTkn; break;
        }
        ch = nextCh();
        return Token(kd);
    }
}

int nextCh()
{
    if (*bufp == '\0') return '\0'; else return *bufp++;
}

void operate(TknKind op)
{
    int d2 = pop(), d1 = pop();
    
    if (op==Divi && d2==0) { cout << " division by 0\n"; errF = 1; }
    if(errF) return;
    switch (op){
        case Plus: push(d1+d2); break;
        case Minus: push(d1-d2); break;
        case Multi: push(d1*d2); break;
        case Divi: push(d1/d2); break;
    }
}

void push(int n)
{
    if (errF)return;
    if (stkct+1 > STK_SIZ) { cout << "stack overflow\n"; exit(1); }
    stack[++stkct] = n;
}

int pop()
{
    if (errF) return 1;
    if (stkct < 1) { cout << "stack underflow\n"; exit(1); }
    return stack[stkct--];
}

void chkTkn(TknKind kd)
{
    if (token.kind != kd) errF = 1;
}

逆ポーランド記法

aからzまでの文字変数名と、一桁の数字を入力できます。

/*--------------------------------*/
/* 逆ポーランド記法の評価polish_p.cpp */
/*--------------------------------*/
#include 
#include 
#include 
using namespace std;

void polish(char *s);
int execute();
int getvalue(int ch);
int order(int ch);
void push(int n);
int pop();

#define STK_SIZ 20
int stack[STK_SIZ+1];
int stkct;
char plsh_out[80];

int main()
{
    char siki[80];
    int ans;
    
    cout << "入力:"; cin.getline(siki, 80);
    polish(siki);
    if (plsh_out[0] == '\n') exit(1);
    ans = execute();
    cout << "変換:" << plsh_out << endl;
    cout << "結果:" << ans << endl;
    return 0;
}

void polish(char *s)
{
    int wk;
    char *out = plsh_out;
    
    stkct = 0;
    for(;;) {
        while (isspace(*s)){ ++s; }
        if (*s == '\0'){
            while (stkct > 0){
                if ((*out++ = pop()) == '('){
                    puts("'('が不正\n"); exit(1);
                }
            }
            break;
        }
        if (islower(*s) || isdigit(*s)){
            *out++ = *s++; continue;
        }
        switch(*s) {
                case '(':
                push(*s);
                break;
                case ')':
                while ((wk = pop()) != '('){
                    *out++ = wk;
                    if(stkct == 0){ puts("'('が不足\n"); exit(1);}
                }
                break;
            default:
                if (order(*s) == -1){
                    cout << "不正な文字: " << *s << endl; exit(1);
                }
                while (stkct>0 && (order(stack[stkct]) >= order(*s))){
                    *out++ = pop();
                }
                push(*s);
        }
        s++;
    }
    *out = '\0';
}

int execute()
{
    int d1, d2;
    char *s;
    
    stkct = 0;
    for(s=plsh_out; *s; s++){
        if(islower(*s))
            push(getvalue(*s));
        else if (isdigit(*s))
            push(*s - '0');
        else {
            d2 = pop(); d1 = pop();
            switch(*s){
                case '+': push(d1+d2); break;
                case '-': push(d1-d2); break;
                case '*': push(d1*d2); break;
                case '/': if (d2 == 0){ puts("ゼロ除算"); exit(1); }
                    push(d1/d2); break;
            }
        }
    }
    if (stkct != 1){ cout << "ERROR\n"; exit(1); }
    return pop();
}

int getvalue (int ch)
{
    if (islower(ch)) return ch-'a' + 1;
    return 0;
}

int order(int ch)
{
    switch (ch){
        case '*': case '/': return 3;
        case '+': case '-': return 2;
        case '(': return 1;
    }
    return -1;
}

void push(int n)
{
    if (stkct+1 > STK_SIZ) { puts("stack overflow"); exit(1); }
    stack[++stkct] = n;
}

int pop()
{
    if (stkct < 1){ puts("stack underflow"); exit(1); }
    return stack[stkct--];
}