LR1語法分析C++實現:一、項目集簇的生成

轉載請註明出處: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章