给定以下的EBNF:
lexp --> atom | list
atom --> number | identifier
list --> (lexp - seq)
lexp-seq --> lexp lexp-seq'
lexp-seq' --> lexp lexp-seq'| ε
打印出编译器分析栈的选择判断过程,look ahead为1。
运行结果截图
实现代码
/* A sample parser for grammar 4.8,C++11 environment is needed.
* After eliminating the left recursion,the following EBNF is obtained.
* lexp --> atom | list
* atom --> number | identifier
* list --> (lexp - seq)
* lexp-seq --> lexp lexp-seq'
* lexp-seq' --> lexp lexp-seq'| ε
*/
#include <iostream>
#include <vector>
#include <cstdlib>
#include <initializer_list>
using namespace std;
typedef vector<string> StackType;
typedef vector<vector<string>> RecordType;
const string ParseStr = "(a(b(2))(c))$";
const int StrLen = ParseStr.size();
int offset = 0;
char LookAhead;
StackType ParseStack = {"$","lexp"};
StackType Actions;
RecordType recorder = {ParseStack};
//Five nonterminals in all
void lexp();
void atom();
void list();
void lexp_seq();
void lexp_seq_1();
void error()
{
fprintf(stderr,"Error!\n");
exit(1);
}
void match(const string &target)
{
int len = target.size();
if(ParseStr.substr(offset,len) == target)
{
offset += len;
// cout<<"match "<<target<<endl;
}
else
error();
}
//Add a step of derivation decision to the ParseStack
void AddRecord(const initializer_list<string>& r)
{
for(auto &r_:r)
{
ParseStack.push_back(r_);
}
recorder.push_back(ParseStack);
}
//Record the derivation dicision
void AddAction(const string &a)
{
Actions.push_back(a);
}
void lexp()
{
LookAhead = ParseStr[offset];
//Pop self
ParseStack.pop_back();
if(LookAhead == '(')
{
AddRecord({"list"});
AddAction("lexp --> list");
list();
}
else if(isdigit(LookAhead) || isalpha(LookAhead))
{
AddRecord({"atom"});
AddAction("lexp --> atom");
atom();
}
else error();
}
void list()
{
//Pop self
ParseStack.pop_back();
AddRecord({")","lexp-seq","("});
AddAction("list --> (lexp-seq)");
match("(");
AddAction("match (");
//Pop '('
ParseStack.pop_back();
recorder.push_back(ParseStack);
lexp_seq();
}
void atom()
{
LookAhead = ParseStr[offset];
//Pop self
ParseStack.pop_back();
if(isalpha(LookAhead))
{
AddRecord({"identifier"});
AddAction("atom --> identifier");
while (isalpha(ParseStr[offset])||isdigit(ParseStr[offset]))
{
string s = ParseStr.substr(offset,1);
match(s);
}
AddAction("match id");
}
else if(isdigit(LookAhead))
{
AddRecord({"number"});
AddAction("atom --> number");
while (isdigit(ParseStr[offset]))
{
string s = ParseStr.substr(offset,1);
match(s);
}
AddAction("match num");
//Don't allow the format like '1xx'
if(isalpha(ParseStr[offset]))
error();
}
else
error();
ParseStack.pop_back();
recorder.push_back(ParseStack);
}
void lexp_seq()
{
//Pop self
ParseStack.pop_back();
AddRecord({"lexp-seq'","lexp"});
AddAction("lexp-seq --> lexp lexp-seq'");
lexp();
lexp_seq_1();
}
void lexp_seq_1()
{
//Pop self
ParseStack.pop_back();
LookAhead = ParseStr[offset];
//lexp-seq'--> ε
if(LookAhead == ')')
{
recorder.push_back(ParseStack);
AddAction("lexp-seq'--> ε");
match(")");
AddAction("match )");
ParseStack.pop_back();
recorder.push_back(ParseStack);
}
else
{
AddRecord({"lexp-seq'","lexp"});
AddAction("lexp-seq'--> lexp lexp-seq'");
lexp();
lexp_seq_1();
}
}
int main()
{
int lineno = 0;
lexp();
match("$");
if (offset == StrLen)
cout<<"Success!"<<endl;
else
error();
AddAction("Accept");
for(auto &s : recorder)
{
for(auto & i : s)
{
cout<<i<<" ";
}
cout<<"\t\t\t\t\t\t\t\t\t\t"<<Actions[lineno]<<endl;
++lineno;
}
return 0;
}