/**************************************/ /* 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; }