{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1},
{15,11,3},
{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1},
{-1,-1,-1}
};
lr.Make("abccba$");
}
}
class LR_analize
{
Stack<char> stack = new Stack<char>();
public char[] term = new char[] { 'i', '+', '*', '$' }, //массив терминалов
neterm = new char[] { 'e', 'E', 'T', 'F' }; //массив нетерминалов
public int[,] netermPrav = new int[,] {
{ 0, -1,},
{ 1, 2 }, //массив правил
{ 3, 4 }, //соответствующих нетерминалу
{ 5, -1 }
};
//массив правил грамматики
public char[][] pravila = new char[][] {
new char[] { 'E', '|', '|' },
new char[] {'E', '+', 'T' },
new char[] { 'T', '|', '|' },
new char[] { 'T', '*', 'F' },
new char[] { 'F', '|', '|' },
new char[] { 'i', '|', '|' }
};
//таблица действий обозначающих тип действия
public string[,] stAction = new string[,] {
{ "s", "-", "-", "-" },
{ "-", "s", "-", "A" },
{ "-", "r", "s", "r" },
{ "-", "r", "r", "r" },
{ "s", "-", "-", "-" },
{ "-", "r", "s", "r" },
{ "-", "r", "r", "r" },
{ "s", "-", "-", "-" },
{ "-", "r", "r", "r" }
};
//таблица переходов
public int[,] tGoto = new int[,] {
{ 1, 2, 3 },
{ -1, -1, -1 },
{ -1, -1, -1 },
{ -1, -1, -1 },
{ -1, 5, 3 },
{ -1, -1, -1 },
{ -1, -1, -1 },
{ -1, -1, 8 },
{ -1, -1, -1 }
},
//таблица действий обозначающих нужное состояние
itAction = new int[,] {
{6,-1,-1,-1},
{-1,4,-1,0},
{-1,2,7,2},
{-1,4,4,4},
{6,-1,-1,-1},
{-1,1,7,1},
{-1,5,5,5},
{6,-1,-1,-1},
{-1,3,3,3}
};
char[] inString;
public void Make(string input)
{
int i=0;
inString = input.ToArray();
Console.WriteLine("Input string: {0}", input);
char inSym = inString[i];
stack.Push('0'); //помещаем в стек начальное состояние
while (inSym != '$' || !stack.Peek().Equals('e') ) // пока входной символ не $ или верхний символ стека не "е"
{
int inSymInd = FindIndexBySym(inSym), //находим индекс входного символа
indS = stack.Peek() - 48; //индекс состояния наверху стека
if (stAction[indS, inSymInd].Equals("s")) //если Shift, то
{
stack.Push(term[inSymInd]); //помещаем терминал на вершину стека
stack.Push((char)(itAction[indS, inSymInd] + 48)); //помещаем соответствующее состояние на вершину стека
inSym = inString[++i]; //переходим к следующеиму входному символу
}
else if (stAction[indS, inSymInd].Equals("r")) //если Reduce, то
{
for (int j = 0; j < 2*countMass(itAction[indS, inSymInd]); j++)
stack.Pop(); //удаляем с вершины стека элементы количеством 2*|w|
int prevS = stack.Peek() - 48;
stack.Push((char)(neterm[findPrav(itAction[indS, inSymInd])])); //помещаем на вершину стека правило из таблицы itAction
if (!inSym.Equals('i')) { inSym = stack.Peek(); inSymInd = FindIndexBySym(inSym)-1; }
stack.Push((char)(tGoto[prevS, inSymInd] + 48)); //помещаем на вершину стека состояние соответствующее текущему правилу
inSym = inString[i];
inSymInd = FindIndexBySym(inSym);
char str1 = neterm[findPrav(itAction[indS, inSymInd])];
int fp = itAction[indS, inSymInd];
string str2 = printPrav(fp);
Console.WriteLine("{0}->{1}", str1, str2); //вывод правила для свертки
}
else if (stAction[indS, inSymInd] == "A") //если Accept, то
{
return; //завершаем программу
}
else { error(); return; }
}
}
int FindIndexBySym(char input) //нахождение индекса териминала или нетерминала
{
for (int j = 0; j < term.Length; j++) if (input == term[j]) return j;
for (int j = 0; j < neterm.Length; j++) if (input == neterm[j]) return j;
return -1;
}
string printPrav(int prav)
{
string str = "";
foreach (char x in pravila[prav])
if (x != '|') str += x;
str += " (" + prav + ")";
return str;
}
int findPrav(int input)
{
int width = 3, height = 4;
for(int i=0;i<height;i++)
for (int j = 0; j < width; j++)
{
if (netermPrav[i, j] == input) return i;
}
return -1;
}
int countMass(int prav)
{
int count = 0;
foreach (char x in pravila[prav])
if (x != '|') count++;
return count;
}
void error()
{
Console.WriteLine("ERROR!!!!!");
}
}
Приложение В
Скриншот работы программы
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.