bool parse(const char *subEngineString) { // Ignore whitespaces subEngineString = parseWhitespaces(subEngineString); // Extract engine identifier. It can be empty at this point const char *beginOfIdentifier = subEngineString; subEngineString = parseIdentifier(subEngineString); engineName.assign(beginOfIdentifier, subEngineString - beginOfIdentifier); // Ignore whitespaces subEngineString = parseWhitespaces(subEngineString); // String termination is allowed at this place if (!*subEngineString) return true; // Otherwise colon must be specified and engine identifier cannot be empty if (!engineName.length() || (*subEngineString != ':') || (*(subEngineString+1) == '\0')) LOG(FATAL) << "Wrong engine specification"; // Process sub engines subEngineString++; while (true) { // Ignore separators subEngineString = parseSeparators(subEngineString); // String termination is allowed at this place if (!*subEngineString) return true; // Extract sub engine identifier const char *beginOfIdentifier = subEngineString; subEngineString = parseIdentifier(subEngineString); // Identifier can not be empty nor contain invalid characters if (beginOfIdentifier == subEngineString) return false; // Collect all valid sub engine names std::string subEngineName; subEngineName.assign(beginOfIdentifier, subEngineString - beginOfIdentifier); subEngines.push_back(subEngineName); } }
static ASTPtr parseSpecifiedLengthContent(const char** fptr, const char*** wordSourcesPtr, const LengthFunc** lengthFuncsPtr) { assert(**fptr == '\'' || std::isdigit(**fptr) || **fptr == '#'); ASTPtr slc; if (**fptr == '\'') { slc = parseStringLiteral(fptr); } else if (**fptr == '#') { slc = parseRepeatedCharFL(fptr, lengthFuncsPtr); } else { const char* f_at = *fptr; LiteralLength length = parseLiteralLength(fptr); if (**fptr == '\'') { slc.reset(new RepeatedCharLL(f_at, length, parseCharLiteral(fptr))); } else if (**fptr == '[') { Block* block = new Block(f_at, length); slc.reset(block); ++*fptr; parseWhitespaces(fptr); // [ is a token while (**fptr != ']') { if (**fptr == '\'' || std::isdigit(**fptr) || **fptr == '#') { block->addChild(parseSpecifiedLengthContent(fptr, wordSourcesPtr, lengthFuncsPtr)); } else if (**fptr == '{') { block->addWords(parseWords(fptr, wordSourcesPtr)); } else { throw DSLException(*fptr, "Expected ', digit, or # to begin specified-length content, " "or { to begin greedy-length content."); } } ++*fptr; parseWhitespaces(fptr); // ] is a token if (**fptr == '^') { parseTopOrBottomFiller(fptr, &block->topFillers, true); if (**fptr == 'v') { parseTopOrBottomFiller(fptr, &block->bottomFillers, false); } } else if (**fptr == 'v') { parseTopOrBottomFiller(fptr, &block->bottomFillers, false); if (**fptr == '^') { parseTopOrBottomFiller(fptr, &block->topFillers, true); } } } else { throw DSLException(*fptr, "Expected ' or [ after length specifier."); } } return slc; }
static void parseTopOrBottomFiller(const char** fptr, std::vector<FillerPtr>* fillers, bool top) { char firstChar = top ? '^' : 'v'; assert(**fptr == firstChar); ++*fptr; parseWhitespaces(fptr); // ^, v are tokens if (**fptr != '{') { throw DSLException(*fptr, "Expected {."); } ++*fptr; parseWhitespaces(fptr); // { is a token parseFillers(fptr, fillers); if (**fptr != '}') { throw DSLException(*fptr, "Expected }."); } ++*fptr; parseWhitespaces(fptr); // } is a token }
static LiteralLength parseLiteralLength(const char** fptr) { assert(std::isdigit(**fptr)); LiteralLength ll(parseUint(fptr), false); if (**fptr == 's') { ll.shares = true; ++*fptr; } parseWhitespaces(fptr); return ll; }
static FillerPtr parseStringLiteral(const char** fptr) { // TOKEN assert(**fptr == '\''); const char* f_at = *fptr; ++*fptr; std::string str; while (**fptr != '\'') { str += parseCharInsideQuotes(&*fptr, '\''); } ++*fptr; parseWhitespaces(fptr); return FillerPtr(new StringLiteral(f_at, str)); }
static FunctionLength parseFunctionLength(const char** fptr, const LengthFunc** lengthFuncsPtr) { assert(**fptr == '#'); FunctionLength fl(**lengthFuncsPtr, false); ++*lengthFuncsPtr; ++*fptr; if (**fptr == 's') { fl.shares = true; ++*fptr; } parseWhitespaces(fptr); return fl; }
static char parseSilhouetteCharLiteral(const char** fptr) { assert(**fptr == '-'); ++*fptr; if (**fptr != '>') { throw DSLException(*fptr, "Expected > immediately after -."); } ++*fptr; parseWhitespaces(fptr); // -> is a token if (**fptr != '\'') { throw DSLException(*fptr, "Expected char literal after ->."); } return parseCharLiteral(fptr); }
static char parseCharLiteral(const char** fptr) { // TOKEN assert(**fptr == '\''); ++*fptr; if (**fptr == '\'') { throw DSLException(*fptr, "Exected char literial; found '' instead."); } char c = parseCharInsideQuotes(&*fptr, '\''); if (**fptr != '\'') { throw DSLException(*fptr, "Expected closing ' for char literal."); } ++*fptr; parseWhitespaces(fptr); return c; }
static ASTPtr parseWords(const char** fptr, const char*** wordSourcesPtr) { assert(**fptr == '{'); Words* words = new Words(*fptr, **wordSourcesPtr); ++*wordSourcesPtr; ASTPtr ast(words); ++*fptr; parseWhitespaces(fptr); // { is a token if (**fptr == 'w') { ++*fptr; parseWhitespaces(fptr); // w is a token if (**fptr == '-') { words->wordSilhouette = parseSilhouetteCharLiteral(fptr); } parseFillers(fptr, &words->interwordFillers); } else { throw DSLException(*fptr, "Expected w after {."); } if (**fptr != '}') { throw DSLException(*fptr, "Expected }, ->, or interword fillers."); } ++*fptr; parseWhitespaces(fptr); // } is a token return ast; }
static ASTPtr parseFormat(const char** fptr, const char*** wordSourcesPtr, const LengthFunc** lengthFuncsPtr) { parseWhitespaces(fptr); // Will insert all root content as children into a super-root Block. Block* rootsParentBlock = new Block(*fptr, LiteralLength(0, false)); ASTPtr rootsParent(rootsParentBlock); while (**fptr != '\0') { if (**fptr == '\'' || std::isdigit(**fptr)) { ASTPtr root = parseSpecifiedLengthContent(fptr, wordSourcesPtr, lengthFuncsPtr); int rootLength = root->getFixedLength(); if (rootLength == UNKNOWN_COL) { throw DSLException(root->f_at, "Root content must be fixed-length."); } rootsParentBlock->addChild(std::move(root)); rootsParentBlock->length.value += rootLength; } else { throw DSLException(*fptr, "Expected ' or digit."); } } return rootsParent; }