Check for stack overflow
This commit is contained in:
101
src/test.cpp
101
src/test.cpp
@@ -3,6 +3,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -427,7 +428,9 @@ struct Parser2 {
|
|||||||
|
|
||||||
// Returns false to reject
|
// Returns false to reject
|
||||||
[[nodiscard]] bool parse() {
|
[[nodiscard]] bool parse() {
|
||||||
stack.push_back(N_VALUE);
|
if (!push({N_VALUE})) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
nextToken();
|
nextToken();
|
||||||
return keepGoing(this);
|
return keepGoing(this);
|
||||||
}
|
}
|
||||||
@@ -437,6 +440,8 @@ struct Parser2 {
|
|||||||
Parser2(Parser2 &&) = delete;
|
Parser2(Parser2 &&) = delete;
|
||||||
Parser2 &operator=(Parser2 &&) = delete;
|
Parser2 &operator=(Parser2 &&) = delete;
|
||||||
|
|
||||||
|
static constexpr int kMaxStackSize = 1 << 10;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Helpers
|
// Helpers
|
||||||
void maybeSkipWs() {
|
void maybeSkipWs() {
|
||||||
@@ -499,24 +504,25 @@ private:
|
|||||||
|
|
||||||
void printStack() {
|
void printStack() {
|
||||||
printf("token: %s\n", symbolNames[currentToken]);
|
printf("token: %s\n", symbolNames[currentToken]);
|
||||||
for (auto s : stack) {
|
for (int i = 0; i < stackPtr - stack; ++i) {
|
||||||
printf("%s ", symbolNames[s]);
|
printf("%s ", symbolNames[stack[i]]);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRESERVE_NONE static bool tokenMatch(Parser2 *self) {
|
||||||
|
self->pop();
|
||||||
|
self->nextToken();
|
||||||
|
MUSTTAIL return keepGoing(self);
|
||||||
|
}
|
||||||
|
|
||||||
PRESERVE_NONE static bool keepGoing(Parser2 *self) {
|
PRESERVE_NONE static bool keepGoing(Parser2 *self) {
|
||||||
// self->printStack();
|
// self->printStack();
|
||||||
if (self->stack.empty()) {
|
if (self->empty()) {
|
||||||
assert(self->currentToken == T_EOF);
|
assert(self->currentToken == T_EOF);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (self->stack.back() == self->currentToken) {
|
MUSTTAIL return table[*(self->stackPtr - 1)][self->currentToken](self);
|
||||||
self->stack.pop_back();
|
|
||||||
self->nextToken();
|
|
||||||
MUSTTAIL return keepGoing(self);
|
|
||||||
}
|
|
||||||
MUSTTAIL return table[self->stack.back()][self->currentToken](self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PRESERVE_NONE static bool reject(Parser2 *) { return false; }
|
PRESERVE_NONE static bool reject(Parser2 *) { return false; }
|
||||||
@@ -524,11 +530,10 @@ private:
|
|||||||
assert(self->currentToken == T_LBRACE);
|
assert(self->currentToken == T_LBRACE);
|
||||||
self->callbacks->on_begin_object(self->data);
|
self->callbacks->on_begin_object(self->data);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
self->stack.push_back(N_OBJECT_MAYBE_CONTINUE);
|
if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
|
||||||
self->stack.push_back(N_VALUE);
|
return false;
|
||||||
self->stack.push_back(T_COLON);
|
}
|
||||||
self->stack.push_back(T_STRING);
|
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool atom(Parser2 *self) {
|
PRESERVE_NONE static bool atom(Parser2 *self) {
|
||||||
@@ -545,54 +550,55 @@ private:
|
|||||||
self->callbacks->on_end_number(self->data);
|
self->callbacks->on_end_number(self->data);
|
||||||
}
|
}
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool string(Parser2 *self) {
|
PRESERVE_NONE static bool string(Parser2 *self) {
|
||||||
assert(self->currentToken == T_STRING);
|
assert(self->currentToken == T_STRING);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool array(Parser2 *self) {
|
PRESERVE_NONE static bool array(Parser2 *self) {
|
||||||
assert(self->currentToken == T_LBRACKET);
|
assert(self->currentToken == T_LBRACKET);
|
||||||
self->callbacks->on_begin_array(self->data);
|
self->callbacks->on_begin_array(self->data);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
self->stack.push_back(N_ARRAY_MAYBE_CONTINUE);
|
if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
|
||||||
self->stack.push_back(N_VALUE);
|
return false;
|
||||||
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool continueArray(Parser2 *self) {
|
PRESERVE_NONE static bool continueArray(Parser2 *self) {
|
||||||
assert(self->currentToken == T_COMMA);
|
assert(self->currentToken == T_COMMA);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
self->stack.push_back(N_ARRAY_MAYBE_CONTINUE);
|
if (!self->push({N_VALUE, N_ARRAY_MAYBE_CONTINUE})) {
|
||||||
self->stack.push_back(N_VALUE);
|
return false;
|
||||||
|
}
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool continueObject(Parser2 *self) {
|
PRESERVE_NONE static bool continueObject(Parser2 *self) {
|
||||||
assert(self->currentToken == T_COMMA);
|
assert(self->currentToken == T_COMMA);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
self->stack.push_back(N_OBJECT_MAYBE_CONTINUE);
|
if (!self->push({T_STRING, T_COLON, N_VALUE, N_OBJECT_MAYBE_CONTINUE})) {
|
||||||
self->stack.push_back(N_VALUE);
|
return false;
|
||||||
self->stack.push_back(T_COLON);
|
}
|
||||||
self->stack.push_back(T_STRING);
|
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool finishArray(Parser2 *self) {
|
PRESERVE_NONE static bool finishArray(Parser2 *self) {
|
||||||
assert(self->currentToken == T_RBRACKET);
|
assert(self->currentToken == T_RBRACKET);
|
||||||
self->callbacks->on_end_array(self->data);
|
self->callbacks->on_end_array(self->data);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
PRESERVE_NONE static bool finishObject(Parser2 *self) {
|
PRESERVE_NONE static bool finishObject(Parser2 *self) {
|
||||||
assert(self->currentToken == T_RBRACE);
|
assert(self->currentToken == T_RBRACE);
|
||||||
self->callbacks->on_end_object(self->data);
|
self->callbacks->on_end_object(self->data);
|
||||||
self->nextToken();
|
self->nextToken();
|
||||||
self->stack.pop_back();
|
self->pop();
|
||||||
MUSTTAIL return keepGoing(self);
|
MUSTTAIL return keepGoing(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,7 +620,7 @@ private:
|
|||||||
/*T_EOF*/
|
/*T_EOF*/
|
||||||
{
|
{
|
||||||
/*T_INVALID*/ reject,
|
/*T_INVALID*/ reject,
|
||||||
/*T_EOF*/ reject,
|
/*T_EOF*/ tokenMatch,
|
||||||
/*T_LBRACE*/ reject,
|
/*T_LBRACE*/ reject,
|
||||||
/*T_RBRACE*/ reject,
|
/*T_RBRACE*/ reject,
|
||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ reject,
|
||||||
@@ -628,7 +634,7 @@ private:
|
|||||||
{
|
{
|
||||||
/*T_INVALID*/ reject,
|
/*T_INVALID*/ reject,
|
||||||
/*T_EOF*/ reject,
|
/*T_EOF*/ reject,
|
||||||
/*T_LBRACE*/ reject,
|
/*T_LBRACE*/ tokenMatch,
|
||||||
/*T_RBRACE*/ reject,
|
/*T_RBRACE*/ reject,
|
||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ reject,
|
||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ reject,
|
||||||
@@ -642,7 +648,7 @@ private:
|
|||||||
/*T_INVALID*/ reject,
|
/*T_INVALID*/ reject,
|
||||||
/*T_EOF*/ reject,
|
/*T_EOF*/ reject,
|
||||||
/*T_LBRACE*/ reject,
|
/*T_LBRACE*/ reject,
|
||||||
/*T_RBRACE*/ reject,
|
/*T_RBRACE*/ tokenMatch,
|
||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ reject,
|
||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ reject,
|
||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ reject,
|
||||||
@@ -656,7 +662,7 @@ private:
|
|||||||
/*T_EOF*/ reject,
|
/*T_EOF*/ reject,
|
||||||
/*T_LBRACE*/ reject,
|
/*T_LBRACE*/ reject,
|
||||||
/*T_RBRACE*/ reject,
|
/*T_RBRACE*/ reject,
|
||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ tokenMatch,
|
||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ reject,
|
||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ reject,
|
||||||
/*T_LBRACKET*/ reject,
|
/*T_LBRACKET*/ reject,
|
||||||
@@ -670,7 +676,7 @@ private:
|
|||||||
/*T_LBRACE*/ reject,
|
/*T_LBRACE*/ reject,
|
||||||
/*T_RBRACE*/ reject,
|
/*T_RBRACE*/ reject,
|
||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ reject,
|
||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ tokenMatch,
|
||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ reject,
|
||||||
/*T_LBRACKET*/ reject,
|
/*T_LBRACKET*/ reject,
|
||||||
/*T_RBRACKET*/ reject,
|
/*T_RBRACKET*/ reject,
|
||||||
@@ -684,7 +690,7 @@ private:
|
|||||||
/*T_RBRACE*/ reject,
|
/*T_RBRACE*/ reject,
|
||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ reject,
|
||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ reject,
|
||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ tokenMatch,
|
||||||
/*T_LBRACKET*/ reject,
|
/*T_LBRACKET*/ reject,
|
||||||
/*T_RBRACKET*/ reject,
|
/*T_RBRACKET*/ reject,
|
||||||
/*T_COLON*/ reject,
|
/*T_COLON*/ reject,
|
||||||
@@ -698,7 +704,7 @@ private:
|
|||||||
/*T_COMMA*/ reject,
|
/*T_COMMA*/ reject,
|
||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ reject,
|
||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ reject,
|
||||||
/*T_LBRACKET*/ reject,
|
/*T_LBRACKET*/ tokenMatch,
|
||||||
/*T_RBRACKET*/ reject,
|
/*T_RBRACKET*/ reject,
|
||||||
/*T_COLON*/ reject,
|
/*T_COLON*/ reject,
|
||||||
},
|
},
|
||||||
@@ -712,7 +718,7 @@ private:
|
|||||||
/*T_ATOM*/ reject,
|
/*T_ATOM*/ reject,
|
||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ reject,
|
||||||
/*T_LBRACKET*/ reject,
|
/*T_LBRACKET*/ reject,
|
||||||
/*T_RBRACKET*/ reject,
|
/*T_RBRACKET*/ tokenMatch,
|
||||||
/*T_COLON*/ reject,
|
/*T_COLON*/ reject,
|
||||||
},
|
},
|
||||||
/*T_COLON*/
|
/*T_COLON*/
|
||||||
@@ -726,7 +732,7 @@ private:
|
|||||||
/*T_STRING*/ reject,
|
/*T_STRING*/ reject,
|
||||||
/*T_LBRACKET*/ reject,
|
/*T_LBRACKET*/ reject,
|
||||||
/*T_RBRACKET*/ reject,
|
/*T_RBRACKET*/ reject,
|
||||||
/*T_COLON*/ reject,
|
/*T_COLON*/ tokenMatch,
|
||||||
},
|
},
|
||||||
/*N_VALUE*/
|
/*N_VALUE*/
|
||||||
{
|
{
|
||||||
@@ -853,7 +859,22 @@ private:
|
|||||||
int len;
|
int len;
|
||||||
const Callbacks *const callbacks;
|
const Callbacks *const callbacks;
|
||||||
void *const data;
|
void *const data;
|
||||||
std::vector<Symbol> stack;
|
Symbol stack[kMaxStackSize];
|
||||||
|
Symbol *stackPtr = stack;
|
||||||
|
bool empty() { return stackPtr == stack; }
|
||||||
|
void pop() {
|
||||||
|
assert(!empty());
|
||||||
|
--stackPtr;
|
||||||
|
}
|
||||||
|
[[nodiscard]] bool push(std::initializer_list<Symbol> symbols) {
|
||||||
|
if (stackPtr >= std::end(stack) - symbols.size()) [[unlikely]] {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = symbols.size() - 1; i >= 0; --i) {
|
||||||
|
*stackPtr++ = *(symbols.begin() + i);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string json = R"({
|
const std::string json = R"({
|
||||||
|
|||||||
Reference in New Issue
Block a user