/*****************************/
/*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);
}
Category: C++
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--]; }