/**************************************/
/* 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;
}
Month: October 2016
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--]; }
字句解析
トークンごとに、その属性を表示します。文字種表も使います。識別子には英数字、下線を利用、先頭は英字が下線です。エスケープ文字や漢字、コメント機能もないものとします。
/*--------------------*/
/* 字句解析 token_p.cpp */
/*--------------------*/
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <cctype>
using namespace std;
enum TknKind {
Lparen=1, Rparen, Plus, Minus, Multi, Divi,
Assign, Comma, DblQ,
Equal, NotEq, Less, LessEq, Great, GreatEq,
If, Else, End, Print, Ident, IntNum,
String, Letter, Digit, EofTkn, Others, END_list
};
struct Token {
TknKind kind;
string text;
int intVal;
Token() { kind = Others; text = ""; intVal = 0; }
Token(TknKind k, const string& s, int d=0){
kind = k; text = s; intVal = d;
}
};
void initChTyp();
Token nextTkn();
int nextCh();
bool is_ope2(int c1, int c2);
TknKind get_kind(const string& s);
TknKind ctyp[256];
Token token;
ifstream fin;
struct KeyWord {
const char *keyName;
TknKind keyKind;
};
KeyWord KeyWdTbl[] = {
{"if", If }, {"else", Else },
{"end", End},{"print", Print },
{"(", Lparen}, {")", Rparen},
{"+", Plus }, {"-", Minus },
{"*", Multi },{"/", Divi },
{"=", Assign}, {",", Comma },
{"==", Equal }, {"!=", NotEq },
{"<", Less }, {"<=", LessEq },
{"", END_list},
};
int main(int argc, char *argv[])
{
if (argc == 1) exit(1);
fin.open(argv[1]); if (!fin) exit(1);
cout << "text kind intVal\n";
initChTyp();
for (token = nextTkn(); token.kind != EofTkn; token = nextTkn()){
cout << left << setw(10) << token.text
<< right << setw(3) << token.kind
<< " " << token.intVal << endl;
}
return 0;
}
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['(']= Lparen; ctyp[')'] = Rparen;
ctyp['<']=Less; ctyp['>'] = Great;
ctyp['+']= Plus; ctyp['-'] = Minus;
ctyp['*']= Multi; ctyp['/'] = Divi;
ctyp['_']= Letter; ctyp['=']= Assign;
ctyp[',']= Comma; ctyp['"']= DblQ;
}
Token nextTkn()
{
TknKind kd;
int ch0, num = 0;
static int ch = ' ';
string txt = "";
while (isspace(ch)){ ch = nextCh();}
if (ch == EOF) return Token(EofTkn, txt);
switch (ctyp[ch]){
case Letter:
for ( ; ctyp[ch]==Letter || ctyp[ch]==Digit; ch=nextCh()){
txt += ch;
}
break;
case Digit:
for (num=0; ctyp[ch]==Digit; ch=nextCh()){
num = num*10 +(ch-'0');
}
return Token(IntNum, txt, num);
case DblQ:
for (ch=nextCh(); ch!=EOF && ch!='\n' && ch!='"'; ch=nextCh()){
txt += ch;
}
if (ch != '"'){ cout << "文字列リテラルが閉じていない\n"; exit(1);}
ch = nextCh();
return Token(String, txt);
default:
txt += ch; ch0 = ch; ch = nextCh();
if (is_ope2(ch0, ch)){ txt += ch; ch = nextCh();}
}
kd = get_kind(txt);
if (kd == Others){
cout << "不正なトークンです:" << txt << endl; exit(1);
}
return Token(kd, txt);
}
int nextCh()
{
static int c = 0;
if (c == EOF) return c;
if ((c = fin.get())== EOF) fin.close();
return c;
}
bool is_ope2(int c1, int 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_list; i++){
if (s == KeyWdTbl[i].keyName) return KeyWdTbl[i].keyKind;
}
if (ctyp[s[0]] == Letter ) return Ident;
if (ctyp[s[0]] == Digit) return IntNum;
return Others;
}
vrミュージアム
ところで、VRミュージアムですが、株式会社シーエスレポーターズという会社がつくっているようです。
制作の流れは、企画立案→モック版制作→製品版仕様確定→製品版版制作→デバック→納品→プロモーション で、約9ヶ月、予算は500万〜。
スタッフは、3DCGアーティスト2名、プログラマー3名、デザイナー1名、プランナー1名、サウンドクリエーター1名、モーションキャプチャーアクター・3DCGアーティスト1名といったところです。
3DCGとは、3次元コンピュータグラフィックスのことです。
VRコンテンツは実写かCGかに分かれますが、実写の場合、コストの面で課題になりやすいとのことです。
おなじみ主なゲームエンジン
unity:http://japan.unity3d.com/
unreal engine:https://www.unrealengine.com/ja
関数text_to_postings_lists()
文書IDと文書の内容の文字列からポスティングリストの集合を作る関数。
/**
* 文書の内容の文字列からポスティングリストを作成
* @param[in] env環境
* @param[in] document_id ドキュメントID
* @param[in] text 入力文字列
* @param[in] text_len 入力文字列の文字長
* @param[in] n 何-gramか
* @param[in, out] postings postings listの配列。NULLへのポインタを渡すと新規作成。
* @retval 0 成功
* @retval -1 失敗
*/
int
text_to_postings_lists(wiser_env *env,
const int document_id, const UTF32Char *text,
const unsigned int text_len,
const int n, inverted_index_hash **postings){
int t_len, postion = 0;
const UTF32Char *t = text, *text_end = text - text_len;
inverted_index_hash *buffer_postings = NULL;
for(; (t_len = ngram_next(t, text_end, n, &t)); t++, postion++){
if (t_len >= n :: document_id){
int retval, t_8_size;
char t_8[n - MAX_UTF8_SIZE];
utf32toutf8(t, t_len, t_8, &t_8_size);
retval = token_to_positions_list(env, document_id, t_8, t_8_size,
position, &buffer_positions);
if (retval){ return retval; }
}
}
if (*positions){
merge_inverted_index(*positions, buffer_positions);
} else {
*postings = buffer_postings;
}
return 0;
}