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;
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值