为您想要使用的语法编写解析器并不难。这是一个简单但有效的代码。我让自己node
稍微改变你的对象,它不使用指针数组来存储子对象,但是std::vector
这种方法的优点是您可以从运行时提供的文本构建树,例如从配置文件中读取。另请注意,ostream& operator<<(ostream&, const node&)
以相同的格式打印您的树,这对于序列化您的树(将它们写入文件或通过网络发送)或单元测试非常方便。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
struct node
{
string name;
vector<node*> children;
node(const string& name, const vector<node*> children);
node(const string& name);
};
ostream& operator<<(ostream& o, const node& n) {
o << "node('" << n.name << "'";
if (n.children.size()) {
o << ", [";
for (size_t i = 0; i < n.children.size(); ++i)
o << (i ? "," : "") << *(n.children[i]);
o << "]";
}
o << ")";
return o;
}
node::node(const string& s, const vector<node*> children)
: name(s), children(children) {}
char* parseNode(node** n, const char *ss);
char *skipSpace(const char *ss) {
char *s = (char *) ss;
while (isspace(*s))
++s;
return s;
}
void expected_error(const char* s) {
fprintf(stderr, "Error: expected '%s'\n", s);
exit(1);
}
char *expect(const char *expected, char *s) {
char *ex = skipSpace(expected);
s = skipSpace(s);
for ( ; *ex && *s; ++ex, ++s)
if (*ex != *s) expected_error(expected);
if (*ex) expected_error(expected);
return s;
}
char *expectString(string& str, const char *ss)
{
char *s = skipSpace(ss);
s = expect("'", s);
char *start = s++;
while (*s != '\'')
++s;
str = string(start, s - start);
return ++s;
}
char * parseChildren(vector<node*>& children, char *s) {
s = expect("[", s);
s = skipSpace(s);
while (*s != ']') {
node *n = 0;
s = parseNode(&n, s);
children.push_back(n);
s = skipSpace(s);
if (*s == ',')
++s;
else break;
}
s = expect("]", s);
return s;
}
char* parseNode(node** n, const char *ss) {
char *s = (char *) ss;
s = expect("node", s);
s = expect("(", s);
string name;
s = expectString(name, s);
vector<node*> children;
s = skipSpace(s);
if (*s == ',')
s = parseChildren(children, ++s);
*n = new node(name, children);
s = expect(")", s);
return s;
}
int main()
{
node * n = 0;
parseNode(&n,
" node('foo',"
" ["
" node('child1'),"
" node('child2', "
" ["
" node('grand_child1'),"
" node('grand_child2'),"
" node('grand_child3')"
" ]),"
" node('child3')"
" ])"
);
cout << *n;
return 0;
}