/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SKSL_NFASTATE #define SKSL_NFASTATE #include <string> #include <vector> #include "LexUtil.h" struct NFAState { enum Kind { // represents an accept state - if the NFA ends up in this state, we have successfully // matched the token indicated by fData[0] kAccept_Kind, // matches the single character fChar kChar_Kind, // the regex '.'; matches any char but '\n' kDot_Kind, // a state which serves as a placeholder for the states indicated in fData. When we // transition to this state, we instead transition to all of the fData states. kRemapped_Kind, // contains a list of true/false values in fData. fData[c] tells us whether we accept the // character c. kTable_Kind }; NFAState(Kind kind, std::vector<int> next) : fKind(kind) , fNext(std::move(next)) {} NFAState(char c, std::vector<int> next) : fKind(kChar_Kind) , fChar(c) , fNext(std::move(next)) {} NFAState(std::vector<int> states) : fKind(kRemapped_Kind) , fData(std::move(states)) {} NFAState(bool inverse, std::vector<bool> accepts, std::vector<int> next) : fKind(kTable_Kind) , fInverse(inverse) , fNext(std::move(next)) { for (bool b : accepts) { fData.push_back(b); } } NFAState(int token) : fKind(kAccept_Kind) { fData.push_back(token); } bool accept(char c) const { switch (fKind) { case kAccept_Kind: return false; case kChar_Kind: return c == fChar; case kDot_Kind: return c != '\n'; case kTable_Kind: { bool value; if ((size_t) c < fData.size()) { value = fData[c]; } else { value = false; } return value != fInverse; } default: ABORT("unreachable"); } } std::string description() const { switch (fKind) { case kAccept_Kind: return "Accept(" + std::to_string(fData[0]) + ")"; case kChar_Kind: { std::string result = "Char('" + std::string(1, fChar) + "'"; for (int v : fNext) { result += ", "; result += std::to_string(v); } result += ")"; return result; } case kDot_Kind: { std::string result = "Dot("; const char* separator = ""; for (int v : fNext) { result += separator; result += std::to_string(v); separator = ", "; } result += ")"; return result; } case kRemapped_Kind: { std::string result = "Remapped("; const char* separator = ""; for (int v : fData) { result += separator; result += std::to_string(v); separator = ", "; } result += ")"; return result; } case kTable_Kind: { std::string result = std::string("Table(") + (fInverse ? "true" : "false") + ", ["; const char* separator = ""; for (int v : fData) { result += separator; result += v ? "true" : "false"; separator = ", "; } result += "]"; for (int n : fNext) { result += ", "; result += std::to_string(n); } result += ")"; return result; } default: ABORT("unreachable"); } } Kind fKind; char fChar = 0; bool fInverse = false; std::vector<int> fData; // states we transition to upon a succesful match from this state std::vector<int> fNext; }; #endif