[cp] SLR 分析表的生成以及分析程序 (1)

 

由於之前寫的發上來後出現了錯誤的格式,以及一些符號替換,而重寫後再發老是超時,因此分成兩個小的 :)

SLR語法分析自動生成程序實驗文檔

1.      在程序中表示文法

1.1        文法的輸入和讀取

爲了程序讀取的方便,非/終結符相互間以空格分開。

例如

應該輸入:

E -> E + T

T -> T * F | T

F -> ( E ) | id

E -> T

而不是輸入:

E->E+T|T

……

      

       文法先保存到文件中然後程序讀取文件。

1.2        文法的拓展

爲了在LR分析時能夠指示分析器正確停止並接受輸入,一般在所有輸入文法前加上一個新的產生式,以上面文法爲例,我們要保存的文法應該是如此:

 

E -> E + T

E -> T * F | T

……

1.3        文法的保存格式

設計一個類Grammar來對文法進行各種處理。

首先把文件中的文法保存到一個序偶表中,以上面的文法爲例子,我們保存的格式類似於下面的表

非終結符

產生試右部

E

E + T

T

T

T * F

T

F

( E )

id

 

也就是說,每一個項是一個2元組,記錄了終結符,和產生式右部。其中非終結符可以用字符串(string)類型表示,產生式右部可用字符串數組( vector<string > )表示。而在保存的同時又可記錄下文法的所有非終結符(因爲文法的產生式左部會出現所有的非終結符),然後再對已經記錄的文法的產生式右部再掃描一遍,記錄下所有的終結符。

在本程序中,我雖然記錄了原始的符號串,但是在具體過程處理時使用的是符號串對應的下標來進行的,因此再對原始形式的文法再掃描一遍,生成對應的以下標形式保存的文法。同時我對終結符號和非終結符號的保存位於不同的數組中,於是下標就會產生衝突,我採用方式是建立一個下標數據結構 Index 來保存下標

 

struct Index

{

  int         index;                 // [非終結符或者終結符的下標]

  bool       teminal;                 // [爲真表示該下標保存的是終結符]

  bool       is_nonteminal();   // [返回! terminal]

}

 

現在往類Grammar 中加入數據成員爲:

 

vector< pair< string,vector<string > > >       m_str_grammar ;    // [記錄以字符串形式保存的文法]

vector< vector<vector<Index > > >                 m_idx_grammar;     // [記錄以下標保存的文法]

MyCollection         m_str_nonteminals; // [記錄原始的非終結符號串]

MyCollection         m_str_terminals;         // [記錄原始的終結符號串]

   

接下來要對文法進行相關處理了。

2.      LR0)項目規範集的生成

2.1        LR0)項目

如果有產生式

E -> A | B

則其對應的所有項目爲

E -> 。A

E > A 。

E -> 。BZ

E -> B 。

其實就是多了一個插在符號之間的點。

項目的數據結構爲

struct Item

{

  int index_of_nont;     // [該項目所在的非終結符位置]

  int index_of_pro;      // [該項目對應該非終結符的產生式位置]

  int index_of_dot;      // [記錄點的位置]

}

 

基於方便(不考慮優化存儲),我把所有的項目保存到一個數組中。

 

Item_0  {0, 0, 0 }數據項

Item_1  {0, 0, 1 }

Item_2  {0, 0, 2 }

……

Item_i  {0, m , n }

……

其中數據類型爲

vector<Item > m_items; // [記錄所有的項目]

2.2             項目集合及其相關運算

一個項目集合包含了多個項目,也等價於後面要建立的自動機的一個狀態。

本程序中對項目集合中存儲的項目,我採取的也是下標形式存儲。因此項目集合的數據結構爲:

/*

 * [項目集合]

 * */

struct Item_c

{

  int         operator[](int index)const;

  size_t      size()const;                                                  

  void        clear();                                      

  void        push_back(int idx);                           

  bool        operator == (const Item_c& item)const;     

  Item_c&       operator = (const Item_c& item);     

  operator       string()const;

private:

  vector<int > index_c;

  hash_set<int >      unique_checker;    // [用於快速的消重]

};

 

之所以爲項目集合新建一個類來封裝一個數組,是爲了能夠支持相等的語義。因爲在之後要建立自動機時會對狀態進行等價判斷,而狀態的類型估計我會直接這樣表示:

 

下面我定義一下項目集合的閉包函數, 在此之前我先定義一個輔助函數:

 

// [返回項目的類型,如果不是規約項目,還返回點的下一位置的符號下標信息]

enum ItemType

{

  IT_R = 0;           // [規約]

  IT_S ,           // [移進]

  IT_A ,           // [接受]

  IT_INVALID         // [非法]

}

/*————————————————————————————————————————————/

 * Desc:      返回項目的類型,如果不是規約項目,返回緊跟着點的符號下標信息    

 * Parm                                                       

/————————————————————————————————————————————*/

ItemType Grammar::get_info_of_next_index(const Item& item, Index& out_index)const

{

  /*

   * [如果點的位置在最後,則表示規約項目]

   * */

  if(item.index_of_dot >= (int)m_idx_grammar[item.index_of_nont][item.index_of_pro].size() )

  {

       // [判斷是否爲接受項目]

        if(m_idx_grammar[item.index_of_nont][item.index_of_pro][ item.index_of_dot - 1] == this->get_pre_idx_start() /*獲得開始符號下標,輸入時的而不是擴展後的*/)

       {

             return IT_A;

       }

        return IT_R;

  }

 

  out_index =  this->m_idx_grammar[item.index_of_nont][item.index_of_pro][item.index_of_dot];

  return IT_S;

}

 

/*————————————————————————————————————————————/

 * Desc: 若項目A->a。Bb  且B->f 是一個產生式           則返回的項目集中包含[B->。f]

 * Parm:                     

/————————————————————————————————————————————*/

vector<int>& Grammar::get_itemc_dot_at_begin(const Index& index,vector<int>& out_itemc)

{

  /*

   * [首先獲得該非終結符的項目開始位置]

   * */

  Item tmp_item(index.index,0,0);

  vector<Item>::const_iterator it = find( m_items.begin(),m_items.end(),tmp_item );  

  if( it != m_items.end() )

  {

        unsigned int idx_pos = unsigned int(it - m_items.begin());

 

        out_itemc.push_back(idx_pos);

        for(unsigned int i=1 ; i<m_idx_grammar[index.index].size(); i++)

       {

             out_itemc.push_back(idx_pos + m_idx_grammar[index.index][i-1].size()+1);

             idx_pos += (int)m_idx_grammar[index.index][i].size()+1;

       }

  }

  return out_itemc;

}

/*————————————————————————————————————————————/

 * Desc:      獲得項目的閉包    

 * Parm                                                       

/————————————————————————————————————————————*/

Item_c& Grammar::closure(Item_c& itemc)

{

  for( unsigned int j = 0; j< itemc.size(); j++ )

  {

        Item item = m_items[itemc[j]];

        Index nxt_index;

        if( IT_S == get_info_of_next_index(item,nxt_index) )

       {

             // [如果是非終結符]

             if( !nxt_index.is_terminal())

             {

                   vector<int> tmp_itemc;

                   get_itemc_of_nont_dot_at_begin(nxt_index, tmp_itemc);

                   for(unsigned int x = 0; x<tmp_itemc.size(); x++)

                        itemc.push_back(tmp_itemc[x]);

             }

       }

  }

  return itemc;

}

 

 

/*————————————————————————————————————————————/

 * Desc:      go_to 運算

 * Parm            -in_item_idx  當前的項目集下標

             -in_idx           符號下標

 * Ret            當前項目集 遇到 符號 到達的項目集的下標

/————————————————————————————————————————————*/

int Grammar::go_to(const int& in_item_idx,      const Index& in_idx)

{

  const Item_c& in_itemc = this->m_item_c_list.GetElement(in_item_idx);

  Item_c out_item;

  for(unsigned int i=0; i<in_itemc.size(); i++)

  {

        Index nxt_idx;

        if(IT_S == this->get_info_of_next_index(m_items[in_itemc[i]],nxt_idx) )

       {

             if(nxt_idx == in_idx)

             {

                  /*

                   * [根據保存的結構可知道,下一個項目的位置是當前項目的位置加一]

                   * */

                   out_item.push_back(in_itemc[i] + 1);

             }

       }

  }

  /*

   * [對該項目集合進行閉包運算]

   * */

  this->closure(out_item);

 

  /*

   * [判斷該項目集合是否已存在,並記錄對應的下標 goto 關係]

   * */

  int pos_of_new_itemc = this->m_item_c_list.indexOf(out_item);

  if(pos_of_new_itemc == this->m_item_c_list.nPos)

  {

        this->m_item_c_list.Add(out_item);

        pos_of_new_itemc = (int)this->m_item_c_list.size() - 1;

  }

 

  return pos_of_new_itemc;

}

 

 

接下來可以生成項目集規範族了,生成的方法是:

1)    獲得項目集合item_c中點的位置的下一個符號的下標集合index_collection

2)    然後對下標集合的每一個下標求goto(item_c, index_collection[i] )

3)    記錄集合之間的狀態轉換信息( DFA )

 

/*—————————————————————————————————/

 * Desc:      生成項目集規範族     

 * Parm                                                       

/—————————————————————————————————*/

void      Grammar::gen_itemc()

{

  Item_c itemc;

  /*

   * [首先生成第一個項目集,包含第一個項目]

   * */

  itemc.push_back(0);

  this->closure(itemc);

 

  /*

   * [加入項目集表中]

   * */

  this->m_item_c_list.Add(itemc);

 

  for(unsigned int i=0; i<this->m_item_c_list.size(); i++)

  {

        const Item_c& cur_itemc = this->m_item_c_list.GetElement(i);

 

        IndexCollection nxt_infos;

        this->get_infos_of_next_index(cur_itemc,nxt_infos);

 

        for(unsigned int j=0; j<nxt_infos.size(); j++)

       {

             const Index& index = nxt_infos.GetElement(j);

             int next_pos_of_itmc = this->go_to(i, index);

 

             /*

              * [設置狀態轉換關係]

              * */

             this->m_dfa.set_next( i, index, next_pos_of_itmc);

       }

  }

  // debug_out("項目集規範族");

  // debug_out(m_item_c_list);

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章