對下列文法,用SLR(1)分析法對任意輸入的符號串進行分析:
(1)S->E
(2)E->E+T
(3)E->T
(4)T->T*F
(5)T->F
(6)F->(E)
(7)F->i
【設計思想】
(1)總控程序,也可以稱為驅動程序。對所有的LR分析器總控程序都是相同的。
(2)分析表或分析函數,不同的文法分析表將不同,同一個文法采用的LR分析器不同時,分析表將不同,分析表又可以分為動作表(ACTION)和狀態轉換(GOTO)表兩個部分,它們都可用二維數組表示。
(3)分析棧,包括文法符號棧和相應的狀態棧,它們均是先進后出棧。
分析器的動作就是由棧頂狀態和當前輸入符號所決定。
- LR分析器由三個部分組成:
- 其中:SP為棧指針,S[i]為狀態棧,X[i]為文法符號棧。狀態轉換表用GOTO[i,X]=j表示,規定當棧頂狀態為i,遇到當前文法符號為X時應轉向狀態j,X為終結符或非終結符。
- ACTION[i,a]規定了棧頂狀態為i時遇到輸入符號a應執行。動作有四種可能:
(1)移進:
action[i,a]= Sj:狀態j移入到狀態棧,把a移入到文法符號棧,其中i,j表示狀態號。
(2)歸約:
action[i,a]=rk:當在棧頂形成句柄時,則歸約為相應的非終結符A,即文法中有A- B的產生式,若B的長度為R(即|B|=R),則從狀態棧和文法符號棧中自頂向下去掉R個符號,即棧指針SP減去R,並把A移入文法符號棧內,j=GOTO[i,A]移進狀態棧,其中i為修改指針后的棧頂狀態。
(3)接受acc:
當歸約到文法符號棧中只剩文法的開始符號S時,並且輸入符號串已結束即當前輸入符是'#',則為分析成功。
(4)報錯:
當遇到狀態棧頂為某一狀態下出現不該遇到的文法符號時,則報錯,說明輸入端不是該文法能接受的符號串。
源程序
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <vector>
#include <string>
#include <utility>
using namespace std;
#define numStates 6
#define numInputs 3
int t(char);
int go(char);
char terminals[numInputs] = { '(', ')', '$' };
string table[numStates][numInputs] =
{ // ( ) $
{ "s:2", "r:S~!", "r:S~!" },
{ "", "", "a:" },
{ "s:2", "r:S~!", "r:S~!" },
{ "", "s:4", "" },
{ "s:2", "r:S~!", "r:S~!" },
{ "", "r:S~(S)S", "r:S~(S)S" }
};
char nonterminals[1] = { 'S' };
int gotos[numStates][1] =
{
{ 1 },
{ -1 },
{ 3 },
{ -1 },
{ 5 },
{ -1 }
};
int main()
{
char k;
const int spacing = 10;
int state;
char in;
string action;
vector < pair < char, int > > stack;
stack.push_back(make_pair('$', 0));
cout << "hello, Press Return to step through parse" << endl << endl;
string input = "()()$";
cout << "Enter your input string to recognize: ";
getline(cin, input);
input += '$';
cout << setfill('=') << left << setw(2 * spacing) << "Stack"
<< setw(2 * spacing) << "Input"
<< setw(2 * spacing) << "Action" << endl << setfill(' ');
while (1)
{
// Display stack
cout << endl;
int u = 0;
for (u = 0; u<stack.size(); u++)
cout << stack[u].first << " " << stack[u].second << " ";
for (; u<7; u++)
cout << " ";
for (int u = input.size(); u<spacing; u++)
cout << " ";
// Display input
cout << setw(spacing) << input;
// Display the action code to take
cout << setw(spacing) << left << action;
state = stack.back().second;
in = input[0];
action = table[state][t(in)];
// Stepping pause
cin.get();
cout << "=> ";
// blank/error cell
if (action == "")
{
cout << "ERROR input not accepted" << endl;
return 0;
}
// Accepted cell
else if (action[0] == 'a')
{
cout << "INPUT STRING ACCEPTED" << endl;
return 0;
}
// Reduction
else if (action[0] == 'r')
{
cout << "Reducing '" << action.substr(4, action.length() - 1)
<< "' on the stack to " << action[2];
for (int i = action.length() - 1; i>3; i--)
{
if (stack.back().first == action[i])
stack.pop_back();
// Epsilons do not consume anything
else if (action[i] == '!')
continue;
else
{
cout << "Error in reduce, expected "
<< stack.back().first << endl;
return 0;
}
}
cout << " Then goto state " << gotos[stack.back().second][go(action[2])] << endl;
stack.push_back(
make_pair(
action[2],
gotos[stack.back().second][go(action[2])]));
}
// Shift
else if (action[0] == 's')
{
cout << "Shifting top of input to stack and moving to state " << action[2] << endl;
stack.push_back(
make_pair(
input[0],
action[2] - 48));
input.erase(0, 1);
}
}
return 0;
}
int t(char terminal)
{ // Linear search bad
for (int i = 0; i<numInputs; i++)
if (terminals[i] == terminal)
return i;
cout << "t(): There was an error in look finding '" << terminal << "' in the table." << endl;
return -1;
}
int go(char nterminal)
{ // Linear search bad
for (int i = 0; i<numInputs; i++)
if (nonterminals[i] == nterminal)
return i;
cout << "go(): There was an error in look finding '" << nterminal << "' in the table." << endl;
return -1;
}
結果