XMLベースのプログラミング言語は冗長な記述になるのですが、バイナリXMLを利用することによりXMLを利用しているにも関わらずそれほどスクリプトのデータサイズが増えていません。
#include <map>
#include <string>
#include <vector>
using nlib_ns::exi::XmlStreamWriter;
using nlib_ns::exi::XmlStreamReader;
using nlib_ns::exi::ExiAllocator;
#define N(x) NLIB_EXI_LITERAL(x)
#define M(x) NLIB_EXI_UTF8(x)
typedef std::basic_string< ::nlib_ns::exi::ExiChar> StdString;
const int kBufSize = 1024 * 128;
unsigned char g_buf[kBufSize];
const int kDataBufSize = 1024;
unsigned char g_data_buf[kDataBufSize];
bool SetupScriptXml() {
MemoryOutputStream os(g_data_buf, kDataBufSize);
UniquePtr<XmlStreamWriter> w(XmlStreamWriter::Create(&os));
if (!w.get()) return false;
w->WriteStartDocument();
w->WriteStartElement(N("program"));
w->WriteStartElement(N("var"));
w->WriteAttribute(N("name"), N("result"));
w->WriteAttribute(N("value"), N("0"));
w->WriteEndElement();
w->WriteStartElement(N("var"));
w->WriteAttribute(N("name"), N("i"));
w->WriteAttribute(N("value"), N("0"));
w->WriteEndElement();
w->WriteStartElement(N("while"));
w->WriteStartElement(N("leq"));
w->WriteEmptyElement(N("i"));
w->WriteEmptyElement(N("max"));
w->WriteEndElement();
w->WriteStartElement(N("add"));
w->WriteEmptyElement(N("result"));
w->WriteEmptyElement(N("result"));
w->WriteEmptyElement(N("i"));
w->WriteEndElement();
w->WriteStartElement(N("add"));
w->WriteEmptyElement(N("i"));
w->WriteEmptyElement(N("i"));
w->WriteStartElement(N("value"));
w->WriteAttribute(N("value"), N("1"));
w->WriteEndElement();
w->WriteEndElement();
w->WriteEndElement();
w->WriteEndElement();
w->WriteEndDocument();
w->Close();
return !!*w;
}
typedef std::map<StdString, int> Variables;
Variables g_variables;
int GetValue(const StdString& nameOrVal) {
Variables::const_iterator it;
if ((it = g_variables.find(nameOrVal)) != g_variables.end()) return it->second;
int rval;
return rval;
}
struct FuncStruct {
typedef std::vector<StdString> Args;
typedef int (*Func)(const Args&);
typedef std::map<StdString, Func> Functions;
Func func;
Args args;
int Call() { return func(args); }
bool Setup(XmlStreamReader* r, bool skip_next = false);
static int Leq(const Args& args) {
int lhs = GetValue(args[0]);
int rhs = GetValue(args[1]);
int result = lhs <= rhs ? 1 : 0;
g_variables[N("_")] = result;
return result;
}
static int Add(const Args& args) {
int result = 0;
size_t n = args.size();
for (size_t i = 1; i < n; ++i) result += GetValue(args[i]);
g_variables[args[0]] = result;
g_variables[N("_")] = result;
return result;
}
static Functions functions;
static void Init() {
functions[N("leq")] = &Leq;
functions[N("add")] = &Add;
}
};
FuncStruct::Functions FuncStruct::functions;
bool FuncStruct::Setup(XmlStreamReader* r, bool skipNext) {
if (!skipNext) {
if (!r->HasNext() || r->Next() != XmlStreamReader::START_ELEMENT) return false;
}
const ExiChar* funcname = r->GetLocalName();
Functions::const_iterator it;
if ((it = functions.find(funcname)) == functions.end()) return false;
func = it->second;
int depth = 0;
do {
if (!r->HasNext()) return false;
switch (r->Next()) {
case XmlStreamReader::START_ELEMENT:
if (
StrCmp(N(
"value"), r->GetLocalName()) == 0) {
args.push_back(r->GetAttributeValue(N(""), N("value")));
} else {
args.push_back(r->GetLocalName());
}
++depth;
break;
case XmlStreamReader::END_ELEMENT:
--depth;
break;
default:
break;
}
} while (depth >= 0);
return true;
}
bool SampleExec() {
if (!SetupScriptXml()) return false;
ExiAllocator::Reset();
FuncStruct::Init();
g_variables[N("max")] = 10;
MemoryInputStream is(g_data_buf, kDataBufSize);
UniquePtr<XmlStreamReader> r(XmlStreamReader::Create(&is));
if (!r.get()) return false;
while (r->HasNext()) {
switch (r->Next()) {
case XmlStreamReader::START_ELEMENT: {
const ExiChar* ln = r->GetLocalName();
if (
StrCmp(ln, N(
"var")) == 0) {
int result = GetValue(r->GetAttributeValue(N(""), N("value")));
g_variables[r->GetAttributeValue(N(""), N("name"))] = result;
g_variables[N("_")] = result;
}
else if (
StrCmp(ln, N(
"while")) == 0) {
FuncStruct cond;
std::vector<FuncStruct> execVec;
if (!cond.Setup(r.get())) return false;
if (!r->HasNext()) return false;
while (r->Next() == XmlStreamReader::START_ELEMENT) {
FuncStruct item;
if (!item.Setup(r.get(), true)) return false;
execVec.push_back(item);
}
while (cond.Call()) {
size_t n = execVec.size();
for (size_t i = 0; i < n; ++i) execVec[i].Call();
}
}
else if (
StrCmp(ln, N(
"program")) != 0) {
FuncStruct funcStruct;
bool result = funcStruct.Setup(r.get());
if (!result) return false;
funcStruct.Call();
}
} break;
default:
break;
}
}
nlib_printf(
"result = %d\n", g_variables[N(
"result")]);
return true;
}
bool SampleMain(int, char**) {
if (ExiAllocator::Init(g_buf, kBufSize) != 0) {
return false;
}
bool rval = SampleExec();
ExiAllocator::Finalize();
return rval;
}
NLIB_MAINFUNC