/** * Processes a .lex file and produces .h and .cpp files which implement a lexical analyzer. The .lex * file is a text file with one token definition per line. Each line is of the form: * <TOKEN_NAME> = <pattern> * where <pattern> is either a regular expression (e.g [0-9]) or a double-quoted literal string.
*/
static constexpr constchar HEADER[] = "/*\n" " * Copyright 2017 Google Inc.\n" " *\n" " * Use of this source code is governed by a BSD-style license that can be\n" " * found in the LICENSE file.\n" " */\n" "/*****************************************************************************************\n" " ******************** This file was generated by sksllex. Do not edit. *******************\n" " *****************************************************************************************/\n";
staticvoid writeH(const DFA& dfa, constchar* lexer, constchar* token, const std::vector<std::string>& tokens, constchar* hPath) {
std::ofstream out(hPath);
SkASSERT(out.good());
out << HEADER;
out << "#ifndef SKSL_" << lexer << "\n";
out << "#define SKSL_" << lexer << "\n";
out << "#include \n";
out << "#include \n";
out << "namespace SkSL {\n";
out << "\n";
out << "struct " << token << " {\n";
out << " enum class Kind {\n"; for (const std::string& t : tokens) {
out << " TK_" << t << ",\n";
}
out << " TK_NONE,";
out << R"(
};
staticvoid writeCPP(const DFA& dfa, constchar* lexer, constchar* token, constchar* include, constchar* cppPath) {
std::ofstream out(cppPath);
SkASSERT(out.good());
out << HEADER;
out << "#include \"" << include << "\"\n";
out << "\n";
out << "namespace SkSL {\n";
out << "\n";
size_t states = 0; for (constauto& row : dfa.fTransitions) {
states = std::max(states, row.size());
}
out << "using State = " << (states <= 256 ? "uint8_t" : "uint16_t") << ";\n";
// Find the first character mapped in our DFA.
size_t startChar = 0; for (; startChar < dfa.fCharMappings.size(); ++startChar) { if (dfa.fCharMappings[startChar] != 0) { break;
}
}
// Arbitrarily-chosen character which is greater than startChar, and should not appear in actual // input.
SkASSERT(startChar < 18);
out << "static constexpr uint8_t kInvalidChar = 18;";
out << "static constexpr uint8_t kMappings[" << dfa.fCharMappings.size() - startChar << "] = {"; for (size_t index = startChar; index < dfa.fCharMappings.size(); ++index) {
out << std::to_string(dfa.fCharMappings[index]) << ", ";
}
out << "};\n";
WriteTransitionTable(out, dfa, states);
out << "static const uint8_t kAccepts[" << states << "] = {"; for (size_t i = 0; i < states; ++i) { if (i < dfa.fAccepts.size() && dfa.fAccepts[i] != INVALID) {
out << " " << dfa.fAccepts[i] << ",";
} else {
out << " 255,";
}
}
out << "};\n";
out << "\n";
out << token << " " << lexer << "::next() {";
out << R"( // Note that we cheat here: normally a lexer needs to worry about the case // where a token has a prefix which is not itself a valid token - for instance, // maybe we have a valid token 'while', but 'w', 'wh', etc. are not valid // tokens. Our grammar doesn't have this property, so we can simplify the logic // a bit.
int32_t startOffset = fOffset;
State state = 1; for (;;) { if (fOffset >= (int32_t)fText.length()) { if (startOffset == (int32_t)fText.length() || kAccepts[state] == 255) { return )" << token << "(" << token << R"(::Kind::TK_END_OF_FILE, startOffset, 0);
} break;
}
uint8_t c = (uint8_t)(fText[fOffset] - )" << startChar << R"(); if (c >= )" << dfa.fCharMappings.size() - startChar << R"() {
c = kInvalidChar;
}
State newState = get_transition(kMappings[c], state); if (!newState) { break;
}
state = newState;
++fOffset;
}
Token::Kind kind = ()" << token << R"(::Kind) kAccepts[state]; return )" << token << R"((kind, startOffset, fOffset - startOffset);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.