/**************************************/ /* 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; }
Category: C++
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--]; }
インデクサのオーバーロード
クラスまたは構造体にインデクサを定義すると、a[i]のように、配列同様に、「インデックス」によるアクセスが可能になります。
同じクラスに複数のインデクサを定義することも可能です。その場合は、メソッドのオーバーロードと同様に、パラメータのシグネチャを別々にする必要があります。パラメータの型が同じで、「インデクサの型」だけが異なるインデクサを定義することはできません。
using System; using System.Collections.Generic; using System.Text; namespace Gushwell.Sample { public class Book { public string Name { get; set; } public string Author { get; set; } public string Publisher { get; set; } public string ISBN { get; set; } public Book(string name, string author, string publisher, string isbn) { this.Name = name; this.Author = author; this.Publisher = publisher; this.ISBN = isbn; } } public class BookList { private List<Book> books = new List<Book>(); public void Add(Book book){ books.Add (book); } // インデクサの定義 public Book this[int index]{ get { return books [index]; } } public Book this[string ISBN]{ get { foreach (Book b in books) if (b.ISBN == ISBN) return b; return null; } } } class Program { static void Main(string[] args){ BookList books = new BookList (); books.Add(new Book("こころ", "夏目漱石", "新潮社", "978-4101010137")); books.Add (new Book ("人間失格", "太宰治", "角川書店", "978-4041099124")); Book book1 = books [0]; Console.WriteLine (book1.Name); Book book2 = books ["978-4041099124"]; Console.WriteLine (book2.Name); Console.ReadLine (); } } }
例外の再スロー
キャッチした例外を、そのまま上位層に再度投げることができます。これを例外の再スローといいます。例外を再スローする場合は、「throw」とだけ記述します。例外オブジェクトは指定しません。
using System; using System.IO; namespace ExceptionSample { class Program { static void Main(string[] args){ try { Foo (); } catch (System.ArgumentException) { Console.WriteLine ("FooでArgumentException発生"); } try { Bar (); } catch (System.ArgumentException) { Console.WriteLine ("BarでArgumentException発生"); } Console.ReadLine (); } public static void Foo() { try { Exec (); } catch (System.ArgumentException) { Console.WriteLine ("ExecでArgumentException発生"); } Console.WriteLine ("Foo終了"); } public static void Bar() { try { Exec (); } catch (System.ArgumentException) { Console.WriteLine ("ExecでArgumentException発生"); throw; } Console.WriteLine ("Bar終了"); } public static void Exec(){ throw new System.ArgumentException (); } } }
MainメソッドではFooメソッドとBarメソッドの呼び出し時の例外をキャッチするようにしています。Fooメソッド、Barメソッドの中でも、try-catchで例外処理をしています。
C#の例外処理
例外とは、プログラム実行時に発生するエラーのことです。C#の例外処理機能を使えば、実行中に発生する予期しないエラーや例外的な状況に対処できます。
C#では、「try」「catch」「finally」のキーワードを使って、例外処理を記述します。
最も基本的な書き方を以下に示します。
try { // なんらかの処理 // この中で、例外が発生する可能性あり } catch { // 例外が発生したときに処理したいコード }
例外の発生を検出したい場合は、tryブロック内に記述します。tryブロック内で何らかの例外が発生すると、処理が中断され、catchブロックに処理が遷移します。次のコードで確認してみてください。
using System; namespace Gushwell.Sample { class Program { static void Main(string[] args){ try { int n = 100; string s = Console.ReadLine (); int m = int.Parse (s); int ans = n / m; Console.WriteLine (ans); } catch { Console.WriteLine ("エラーが発生"); } Console.ReadLine (); } } }