轉載請註明出處:https://blog.csdn.net/hhhhhhhhhhkkkkkkkkkk
嗯,先上代碼,後面慢慢寫註釋,我好像太雞智(賊)了,哈哈
生成項目集簇
基本符號的定義與相關操作
using t_sym = int;//符號
using t_vv = t_sym;//終結符+虛擬終結符
using t_vt = t_vv;//終結符
using t_vc = t_vv;//虛擬終結符
using t_vn = t_sym;//非終結符
#define is_vv(x) ((x)>=0)
#define is_vt(x) (((x)>=0)&&((x)<=0xffff))
#define is_vc(x) ((x)>0xffff)
#define is_vn(x) ((x)<0)
語法
產生式
class t_analyzer;
using t_sematic = void(*)(t_analyzer*ana);
using t_syms = std::vector<t_sym>;//符號串
struct t_sen//產生式
{
t_vn left;
t_syms rights;
t_sematic sematic;
t_vv pri_sym;//優先級虛擬符號
};
語法與相關函數
enum e_ass
{
e_ass_none,
e_ass_left,
e_ass_right,
};
using t_vv_pri_ass_map = std::map<t_vv, std::pair<int, e_ass>>;//虛擬符號的優先級與結合性
using t_sens = std::vector<t_sen>;//文法
struct t_grammar//語法
{
t_sens sens;
t_vv_pri_ass_map vv_pri_ass_map;
t_sematic other_sens;
};
void grammar_make_pri_ass(t_grammar&g)
{
//插入默認優先級的處理
g.vv_pri_ass_map.insert({ 0,{ 0,e_ass_none } });
//開始設置語句對應的終結符
for (auto&sen : g.sens)
{
if (sen.pri_sym == 0)//未手動指定優先級和結合性符號
{
//找到右邊起第一個終結符
for (auto rit = sen.rights.rbegin(); rit != sen.rights.rend(); rit++)
{
if (is_vt(*rit))
{
sen.pri_sym = *rit;
break;
}
}
//可能會沒有終結符,這時候就設置不了產生式的優先級
}
}
}
項目集簇
first集與相關函數
using t_first = std::set<t_vt>;//first集
t_first&operator+=(t_first&dst, const t_first&src)
{
for (auto vt : src)
dst.insert(vt);
return dst;
}
項目與相關操作
struct t_item//項目
{
size_t senid;//產生式id
size_t pos;//項目符位置
t_first first;//first集
};
bool operator==(const t_item&item1, const t_item&item2)
{
if (item1.senid != item2.senid)
return false;
if (item1.pos != item2.pos)
return false;
if (item1.first.size() != item2.first.size())
return false;
auto it1 = item1.first.begin();
auto it2 = item2.first.begin();
for (; it1 != item1.first.end(); it1++, it2++)
if (*it1 != *it2)
return false;
return true;
}
bool operator!=(const t_item&item1, const t_item&item2)
{
return !(item1 == item2);
}
using t_items = std::vector<t_item>;//項目集合
bool operator==(const t_items&items1, const t_items&items2)
{
if (items1.size() != items2.size())
return false;
for (size_t i = 0; i < items1.size(); i++)
{
if (items1.at(i) != items2.at(i))
return false;
}
return true;
}
t_items&operator+=(t_items&items, const t_item&item)
{
for (size_t i = 0; i < items.size(); i++)
if (items.at(i) == item)
return items;
items.push_back(item);
return items;
}
項目集
using t_action_map = std::map<t_sym, int>;//動作表(符號->>=0移進,==-1接受,<-1歸約)
enum e_action//動作類型
{
e_error,
e_shift,
e_reduce,
e_access,
};
using t_collision_map = std::map<t_vt, std::map<e_action, std::vector<int>>>;//衝突表
struct t_set//項目集
{
t_items items;
t_action_map action_map;
t_collision_map collision_map;
};
構造項目集簇
生成空推導與非終結符的first集
using t_vn_senids_map = std::map<t_vn, std::vector<size_t>>;//以非終結符爲索引的語句id集合
using t_vn_empty_map = std::map<t_vn, int>;//非終結符的空推導表-1-無法推出空 0-未知 1可推出空
using t_vn_first_map = std::map<t_vn, t_first>;//非終結符的first集表
t_vn_senids_map build_vn_senids_map(const t_sens&sens)
{
t_vn_senids_map vn_senids_map;
for (size_t i = 0; i < sens.size(); i++)
{
const auto&sen = sens.at(i);
vn_senids_map[sen.left].push_back(i);
}
return vn_senids_map;
}
t_vn_empty_map build_vn_empty_map(const t_sens&sens)
{
t_vn_empty_map vn_empty_map;
//生成語法的左部(非終結符)索引,方便操作
std::map<t_vn, std::vector<std::pair<int, int>>> vn_senid_poss_map;
for (int i = 0; i < (int)sens.size(); i++)
{
vn_senid_poss_map[sens.at(i).left].push_back({ i,0 });
}
//設置爲未定
vn_empty_map.clear();
for (const auto&vn : vn_senid_poss_map)
{
vn_empty_map[vn.first] = 0;
}
//對每個非終結符,直接設置
for (auto it0 = vn_senid_poss_map.begin(); it0 != vn_senid_poss_map.end();)
{
auto&vn_senid_poss = *it0;
bool _is_deleted = false;
//對每個產生式
for (auto it = vn_senid_poss.second.begin(); it != vn_senid_poss.second.end(); )
{
const auto&sen = sens.at(it->first);
if (sen.rights.size() > 0)//如果不是空產生式
{
auto sym = sen.rights.at(0);
if (is_vt(sym))//如果第一個符號是終結符,刪掉該產生式
it = vn_senid_poss.second.erase(it);
else
it++;
}
else//有空產生式
{
//置爲‘是’
vn_empty_map.at(vn_senid_poss.first) = 1;
//刪掉該非終結符的所有產生式
it0 = vn_senid_poss_map.erase(it0);
_is_deleted = true;
break;
}
}
//如果未刪
if (!_is_deleted)
{
//如果該非終結符的所有產生式都被刪去
if (vn_senid_poss.second.size() <= 0)
{
//置爲‘否’
vn_empty_map.at(vn_senid_poss.first) = -1;
it0 = vn_senid_poss_map.erase(it0);//既然都沒產生式了,他也沒必要存在了
}
else//自增
it0++;
}
}
while (true)
{
bool is_changed = false;
//間接設置
for (auto it0 = vn_senid_poss_map.begin(); it0 != vn_senid_poss_map.end();)
{
auto&vn_senid_poss = *it0;
bool _is_deleted = false;
//對每個產生式
for (auto it = vn_senid_poss.second.begin(); it != vn_senid_poss.second.end(); )
{
const auto&sen = sens.at(it->first);
auto non = sen.rights.at(it->second);
if (vn_empty_map.find(non) == vn_empty_map.end())
printf("warn: %d undefined\n", non);
if (vn_empty_map[non] == 1)//如果該非終結符在數組中爲‘是’
{
//刪去該終結符
it->second++;
is_changed = true;
//若這使右部爲空
if (it->second >= (int)sen.rights.size())
{
//置該非終結符號爲‘是’
vn_empty_map.at(vn_senid_poss.first) = 1;
//刪掉所有該非終結符的產生式
it0 = vn_senid_poss_map.erase(it0);
_is_deleted = true;
break;
}
it++;
}
else if (vn_empty_map.at(non) = -1)//若爲‘否’
{
//刪去該產生式
it = vn_senid_poss.second.erase(it);
}
else
{
it++;
}
}
//如果未刪
if (!_is_deleted)
{
//如果該非終結符的所有產生式都被刪去
if (vn_senid_poss.second.size() <= 0)
{
//置爲‘否’
vn_empty_map.at(vn_senid_poss.first) = -1;
is_changed = true;
it0 = vn_senid_poss_map.erase(it0);//既然都沒產生式了,他也沒必要存在了
}
else//自增
it0++;
}
}
if (!is_changed)
break;
}
return vn_empty_map;
}
t_vn_first_map build_vn_first_map(const t_sens&sens, const t_vn_empty_map&vn_empty_map)
{
t_vn_first_map vn_first_map;
//構造非終結符的索引,並直接設置
t_vn_senids_map vn_senids_map;
for (size_t i = 0; i < sens.size(); i++)
{
const auto&sen = sens.at(i);
if (sen.rights.size() > 0)
{
if (is_vt(sen.rights.at(0)))
vn_first_map[sen.left].insert(sen.rights.at(0));
else
vn_senids_map[sen.left].push_back({ i });
}
}
//間接設置
int old_size = 0;
while (true)
{
for (auto it0 = vn_senids_map.begin(); it0 != vn_senids_map.end(); it0++)
{
for (auto it = it0->second.begin(); it != it0->second.end(); it++)
{
const auto&sen = sens.at(*it);
for (size_t i = 0; i < sen.rights.size(); i++)
{
auto sym = sen.rights.at(i);
if (is_vn(sym))
{
for (auto ter : vn_first_map[sym])
vn_first_map[it0->first].insert(ter);
if (vn_empty_map.at(it0->first) != 1)
break;
}
else
{
vn_first_map[it0->first].insert(sym);
break;
}
}
}
}
int size = 0;
for (const auto&first_vn : vn_first_map)
{
size += (int)first_vn.second.size();
}
if (size != old_size)
old_size = size;
else
break;
}
return vn_first_map;
}
t_first calc_last_first(const t_item&item, const t_sens&sens, const t_vn_empty_map&vn_empty_map, const t_vn_first_map&vn_first_map)
{
t_first first;
const auto&rights = sens.at(item.senid).rights;
int i;
for (i = item.pos + 1; i < (int)rights.size(); i++)
{
auto v = rights.at(i);
if (is_vn(v))//非終結符
{
//將該vn對應的first併入
first += vn_first_map.at(v);
//如果該vn推導不出空,則結束
if (vn_empty_map.at(v) <= 0)
break;
}
else//終結符,直接結束
{
first.insert(v);
break;
}
}
//如果推導到了產生式末尾,則把項目的first併入
if (i >= (int)rights.size())
first += item.first;
return first;
}
生成項目集簇
//展開項目集合
void expand_items(t_items&items, const t_sens&sens, const t_vn_senids_map&vn_senids_map,const t_vn_empty_map&vn_empty_map, const t_vn_first_map&vn_first_map)
{
//展開
for (size_t i = 0; i < items.size(); i++)
{
const auto&item = items.at(i);
const auto&sen = sens.at(item.senid);
if (item.pos < sen.rights.size())
{
auto sym = sen.rights.at(item.pos);
if (is_vn(sym))
{
const auto&senids = vn_senids_map.at(sym);
auto first = calc_last_first(item, sens, vn_empty_map, vn_first_map);
for (auto senid : senids)
{
items += {senid, 0, first};
}
}
}
}
//合併僅first集不同的項
for (size_t i = 0; i < items.size(); i++)
{
for (size_t j = i + 1; j < items.size(); )
{
auto&item1 = items.at(i);
auto&item2 = items.at(j);
if ((item1.senid == item2.senid) && (item1.pos == item2.pos))
{
item1.first += item2.first;
items.erase(items.begin() + j);
}
else
j++;
}
}
}
std::pair<int, e_ass>get_ass(const t_vv_pri_ass_map&vv_pri_ass_map, int vv)
{
auto it = vv_pri_ass_map.find(vv);
if (it != vv_pri_ass_map.end())
{
return it->second;
}
return { 0,e_ass::e_ass_right };
}
t_cluster cluster_build(const t_grammar&g, t_vt end_vt)
{
//生成vn_senids_map
auto vn_senids_map = build_vn_senids_map(g.sens);
//生成vn_empty_map
auto vn_empty_map = build_vn_empty_map(g.sens);
//生成vn_first_map
auto vn_first_map = build_vn_first_map(g.sens, vn_empty_map);
//開始構造
//添加初始項目集
t_cluster cluster = { { { { 0,0,{ end_vt } } } } };
//對項目集簇中的每個項目集
for (size_t i = 0; i < cluster.size(); i++)
{
auto&set = cluster.at(i);
//展開當前項目集
expand_items(set.items, g.sens, vn_senids_map, vn_empty_map, vn_first_map);
std::map<t_sym, t_items>sym_items_map;
//對項目集合中的每個項目
for (size_t j = 0; j < set.items.size(); j++)
{
const auto&item = set.items.at(j);
const auto&sen = g.sens.at(item.senid);
//如果不是歸約項目,則按項目符號添加到對應的項目集合,同時項目符號後移一位
if (item.pos < sen.rights.size())
{
sym_items_map[sen.rights.at(item.pos)].push_back({ item.senid,item.pos + 1,item.first });
}
}
//對每個符號,生成移進表
for (auto&pr : sym_items_map)
{
auto&new_items = pr.second;
//展開上面生成的項目集合
expand_items(new_items, g.sens, vn_senids_map, vn_empty_map, vn_first_map);
//在項目集簇中查找這個項目集合
auto id = cluster_find(cluster, new_items);
//若未找到,把這個項目集合構成項目集並添加到項目集簇的末尾
if (id >= cluster.size())
{
cluster.push_back({ new_items });
}
//生成該符號的移進表
cluster.at(i).action_map[pr.first] = int(id);
//添加衝突
cluster.at(i).collision_map[pr.first][e_shift].push_back(int(id));
}
//生成歸約表(包括接受表)
auto&new_set = cluster.at(i);
//對當前項目集合的每個項目
for (const auto&item : new_set.items)
{
const auto&sen = g.sens.at(item.senid);
//如果是歸約項目
if (item.pos >= sen.rights.size())
{
//對項目的每個first集符號
for (auto vt : item.first)
{
new_set.collision_map[vt][e_reduce].push_back(int(item.senid));
}
}
}
//處理衝突
/*
默認:
1 移進-歸約->移進
2 歸約-歸約->senid小的歸約
指定:
1 採用優先級大的
2 優先先級相同的按本符號的結合性處理
*/
for (const auto&pr : new_set.collision_map)
{
auto it = pr.second.find(e_reduce);
//有歸約項
if (it != pr.second.end())
{
auto it1 = pr.second.find(e_shift);
//有移進項
size_t j = 0;
if (it1 != pr.second.end())
{
//比較歸約項與移進項的優先級大小
auto pri_shift = get_ass(g.vv_pri_ass_map, pr.first);
for (; j < it->second.size(); j++)
{
auto pri_reduce = get_ass(g.vv_pri_ass_map, g.sens.at(it->second.at(j)).pri_sym);
//如果有優先級大於移進項的,就跳到無移進項的處理,否則結束(採用移進項)
if (pri_shift.first < pri_reduce.first)
break;
else if (pri_shift.first == pri_reduce.first)
{
if (pri_reduce.second == e_ass_left)//採用歸約,所以跳出
break;
}
}
}
if (j < it->second.size())//無移進項,或移進項優先級小
{
auto pri_cur = get_ass(g.vv_pri_ass_map, g.sens.at(it->second.at(j)).pri_sym);
auto cur_senid = it->second.at(j);
for (j++; j < it->second.size(); j++)
{
auto pri_next = get_ass(g.vv_pri_ass_map, g.sens.at(it->second.at(j)).pri_sym);
if (pri_next.first < pri_cur.first)
continue;
if (pri_next.first == pri_cur.first)
{
if (cur_senid >= it->second.at(j))
continue;
}
pri_cur = pri_next;
cur_senid = it->second.at(j);
}
new_set.action_map[pr.first] = -cur_senid - 1;
}
}
//如果沒有歸約項,就不用管了
}
}
return cluster;
}