Я пытаюсь построить NFA из текстового файла в формате:
state 1 start
state 2
state 3 accept
transition 1 0 2
transition 1 1 3
transition 2 0 1
transition 2 0 3
где состояние:
состояние [состояние #] [начать или принять] [начать или принять]
переход: переход [переход состояния из] [символ] [переход состояния в]
Я смог заставить программу работать, пока не было перехода из одного состояния обратно в то же самое состояние. (например: добавление в переход 1 0 1 в файл выше не работает). Я застрял на этом в течение нескольких часов и решил, что мне придется попытаться реализовать способ отслеживания конфигураций, чтобы заставить его работать, чтобы убедиться, что одна и та же конфигурация не пробовалась более одного раза, но я не могу получить это.
Я думал о создании структуры для конфигураций и как-то реализовать ее в функцииvaluInput (), но я застрял на том, как это сделать.
Вот мой код:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <vector>
using namespace std;
string num, currentState, tranState;
char symbol;
struct Transition;
struct State{
bool startS = false;
bool acceptS = false;
string sym;
vector<Transition> transitions;//transition between states
};
struct Transition{
string symb;
State to;
State from;
bool eval = false;
};
struct NFA{
vector<State> NFAStates;
State start;
};
void evaluateInput(string in, NFA F)
{
vector<State> currStates;
vector<State> numAccept;
for(int n = 0; n < F.NFAStates.size(); n++)
{
if(F.NFAStates[n].startS)
{
currStates.push_back(F.NFAStates[n]);
}
}
for(int i = 0; i < in.length(); i++)
{
vector<State> next;
for(int j = 0; j < currStates.size(); j++)
{
int tranSize = currStates[j].transitions.size();
for(int k = 0; k < tranSize; k++)
{
if((currStates[j].transitions[k].eval == false) && (in.at(i) == currStates[j].transitions[k].symb))
{
currStates[j].transitions[k].eval = true;
for(int m = 0; m < F.NFAStates.size(); m++)
{
if(F.NFAStates[m].sym == currStates[j].transitions[k].to.sym)
{
next.push_back(F.NFAStates[m]);
if(F.NFAStates[m].acceptS)
{
numAccept.push_back(F.NFAStates[m]);
}
}
}
}
}
currStates = next;
}
}
if(numAccept.size() > 0)
{
cout << "Accept!" << endl;
}
}
int main(int argc, char* argv[])
{
char* fileName;
string stringInput;
if(argc > 1)
{
fileName = argv[1];
stringInput = argv[2];
//cout << stringInput << endl;
}
ifstream file(fileName);
if(file.is_open())
{
NFA FA;
string line;
while(getline(file, line)){
//cout << "1: " << line << endl;
string ST;
stringstream ss(line);
getline(ss, ST, '\t');
if(ST == "state")
{
State S;
string SoA1;
string SoA2;
getline(ss, num, '\t');
getline(ss, SoA1, '\t');
getline(ss, SoA2);
int num_i = stoi(num);
S.sym = num_i;
if((SoA1 == "start") || (SoA2 == "start"))
{
S.startS = true;
}
if((SoA1 == "accept") || (SoA2 == "accept"))
{
S.acceptS = true;
}
FA.NFAStates.push_back(S);
if(S.startS == true){
FA.start = S;
}
}else if(ST == "transition")
{
Transition T;
string symbol1;
getline(ss, currentState, '\t');
getline(ss, symbol, '\t');
getline(ss, tranState);
symbol = symbol1[0];
int currentState_i = stoi(currentState);
int tranState_i = stoi(tranState);
T.symb = symbol;
for(int j = 0; j < FA.NFAStates.size(); j++)
{
if(FA.NFAStates[j].sym == tranState)
{
T.to = FA.NFAStates[j];
}
}
for(int i = 0; i < FA.NFAStates.size(); i++)
{
if(FA.NFAStates[i].sym == currentState)
{
T.from = FA.NFAStates[i];
FA.NFAStates[i].transitions.push_back(T);
}
}
}
}
evaluateInput(stringInput, FA);
}
}
Спасибо за помощь.
Ваш код не имеет большого смысла, так как у вас есть много (неполных) копий объектов состояния, которые создаются copy-ctor при попытке создать представление конечного автомата.
каждый State
объект содержит вектор Transition
объекты, и каждый Transition
объект в свою очередь содержит два State
объекты, from
а также to
, которые будут копиями State
объекты, созданные в точке, где вы анализируете переходную строку (поэтому будут содержать уже проанализированные переходы, но не те, которые еще не проанализированы).
Было бы гораздо больше смысла, если вы измените Transition
объект для использования State *
или же State &
ссылаться непосредственно на State
задействованные объекты, а не их копирование.
Кроме того, когда вы пытаетесь оценить NFA, вы снова делаете копии состояний, что означает, что вы можете легко получить одно и то же состояние несколько раз в векторах. Было бы больше смысла использовать std::set<State *>
вместо этого. Точно так же в вашем NFA
объект, вы бы предпочли std::map<std::string, State>
чтобы упростить поиск состояний по имени (и чтобы все указатели не становились недействительными при вызове push_back
по вектору)
Других решений пока нет …