我正在编写一个编译时解析,创建列表的库。 我能够让它立即工作的唯一方法是使用我的Node结构的std :: array作为“静态分配的池”,并使用整数索引作为该指针的“指针”。
这很好用,但我不得不修改数组的大小。
这就是我所拥有的:
#include <iostream>
using namespace std;
struct Symbol
{
constexpr Symbol(): pBeg(), pEnd() {}
constexpr Symbol(const char *pBeg, const char *pEnd): pBeg(pBeg), pEnd(pEnd) {}
constexpr int len() { return pEnd - pBeg; }
string getText() const { return string(pBeg, pEnd); }
const char *pBeg;
const char *pEnd;
};
extern void ParseError(const char *s) {cerr << "Parse Error:" << s << endl;}
constexpr bool isAlpha(char ch)
{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
// Raises compiletime error if no more characters left to parse
constexpr const char *checkEOS(const char *pszText)
{
bool eos = !*pszText;
if(eos) ParseError("Unexpected end of stream");
return pszText;
}
// Takes a string literal and returns pointer to first non-whitespace character
constexpr const char *eatSpace(const char *pszText)
{
while(*pszText == ' ' || *pszText == '\n' || *pszText == '\r' || *pszText == '\t')
{
++pszText;
}
return pszText;
}
// Takes a string literal text and tries to consume [a-z]+
constexpr const Symbol eatAlpha(const char *pszText)
{
// Ensure not EOS
checkEOS(pszText);
Symbol sym;
sym.pBeg = pszText;
sym.pEnd = pszText;
while(isAlpha(*sym.pEnd)) sym.pEnd++;
// Ensure at least 1 character is consumed
bool empty_tag = sym.pBeg == sym.pEnd;
if(empty_tag) ParseError("Expecting an identifier");
return sym;
}
struct Node
{
Symbol tag; // pointer to tag name range
const Node &child;
constexpr Node(Symbol tag, const Node child):tag(tag), child(child){}
};
constexpr const Symbol NullSym;
constexpr const Node NullNode{NullSym, NullNode};
constexpr Node parse(const char* text)
{
if(text)
{
text = eatSpace(text);
if(isAlpha(*text))
{
Symbol symTag = eatAlpha(text);
return Node(symTag, parse(symTag.pEnd));
}
}
return NullNode;
}
void dumpNode(const Node &n, int indent = 0)
{
if(&n.child != &NullNode)
{
cerr << n.tag.getText() << endl;
dumpNode(n.child, indent + 1);
}
}
int main()
{
constexpr Node node = parse("attr battr cattr");
dumpNode(node);
}
编译时:
$ g++ --std=c++14 -DSPT_DEBU main4.cpp
main4.cpp:72:48: error: 'Node{Symbol{0, 0}, child}' is not a constant expression
constexpr const Node NullNode{NullSym, NullNode};
^
main4.cpp: In function 'int main()':
main4.cpp:101:49: in constexpr expansion of 'parse(((const char*)"attr battr cattr"))'
main4.cpp:83:44: in constexpr expansion of 'parse(symTag.Symbol::pEnd)'
main4.cpp:83:44: in constexpr expansion of 'parse(symTag.Symbol::pEnd)'
main4.cpp:83:44: in constexpr expansion of 'parse(symTag.Symbol::pEnd)'
main4.cpp:101:49: error: constexpr call flows off the end of the function
constexpr Node node = parse("attr battr cattr");
^
我正在尝试甚至可能吗?
当你通过递归调用嵌套时,我对constexpr值的生命周期有点模糊
我很确定这应该是可能的。毕竟有人写了一个constexpr C编译器。
我需要的是某种动态数据结构,如列表,在编译时不必修复大小。
提前致谢。