/*****************************/ /*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; vectorintercode; 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; n aryLen; 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[n].name == s) return n; } break; case 'L': for (n=startLtable; n<(int)Ltable.size(); n++) { if(Ltable[n].name == s) return n; } break; case 'F': n = searchName(s, 'G'); if(n != -1 && Gtable[n].nmKind==fncId) return n; break; case 'V': if (searchName(s, 'F') != -1) err_exit("関数名と重複しています: ", s); if (s[0] == '$') 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[i]= Others; } for(i='0'; i<='9'; i++){ ctyp[i]= Digit; } for(i='A'; i<='Z'; i++){ ctyp[i]= Letter; } for (i='a'; i<='z'; i++){ ctyp[i]= Letter; } ctyp['_']=Letter; ctyp['$'] = Doll; ctyp['(']= Lparen; ctyp[')']= Rparen; ctyp['[']=Lbracket; ctyp[']']= Rbracket; ctyp['<']=Less; ctyp['>']= 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[0] == '$') 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 != '[') return; token = nextTkn(); if (token.kind != IntNum) err_exit("配列長は正の整数定数で指定してください。", token.text); tmpTb.aryLen = (int)token.dblVal + 1; token = chk_nextTkn(nextTkn(), ']'); if (token.kind == '[') 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--]; }