编译原理实验(算符优先文法)

work.h
 1  #include < iostream >
 2  #include < stdlib.h >
 3  #include < stdio.h >
 4  #include < string .h >
 5 
 6  /* ************STRUCT************ */
 7  #ifndef keyword
 8  #define  keyword
 9  /*
10   * 关键字结构,用于work2.cpp
11   */
12  struct  KEYWORD_NODE{
13       char  val[ 100 ];
14  };
15 
16  /*
17   * 非终结符结构,用于work3.cpp
18   */
19  struct  N_NODE{ // 非终结符
20       char  val; //
21       int  cnt; // 产生式数目
22       char  ARR[ 30 ][ 30 ];
23  };
24  #endif
25 
26  /* ***********FUNCTION*********** */
27  void  init();
28  bool  isLetter( char  ch);
29  void  dealSourceCode();
30  void  morphologyAnalysis();
31  void  dealOperatorPrecedenceGrammar();
32  using  namespace  std;



 

init.cpp
 1  /* **************************************************************\
 2   *Author:Hu Wenbiao
 3   *Created Time: Mon 15 Nov 2010 09:12:44 PM CST
 4   *File Name: init.cpp
 5   *Description:执行各文件所需的初始化操作
 6  \************************************************************** */
 7  // *========================*Head File*========================*\\
 8 
 9  #include " work.h "
10  /* ----------------------*Global Variable*---------------------- */
11  // work2.cpp
12  extern  KEYWORD_NODE KEYWORD[ 30 ];
13  // work3.cpp
14  extern  bool  F[ 30 ][ 30 ],L[ 30 ][ 30 ];
15  extern  N_NODE N_ARRAY[ 30 ];
16  extern  char  T_ARRAY[ 30 ];
17  extern  char  PRECEDENCETABLE[ 30 ][ 30 ];
18  // *=======================*Main Program*=======================* //
19 
20  /*
21   * 设置关键字,用于work2.cpp的初始化
22   */
23  void  setKeyword( int  pos, string  str){
24       int  p = 0 ;
25       while (str[p]){
26          KEYWORD[pos].val[p] = str[p];
27          p ++ ;
28      }
29  }
30 
31  /*
32   * 各文件的初始化
33   */
34  void  init(){
35 
36       /*
37       * work2.cpp
38        */
39      memset(KEYWORD, 0 , sizeof (KEYWORD));
40      setKeyword( 1 , " const " );
41      setKeyword( 2 , " var " );
42      setKeyword( 3 , " procedure " );
43      setKeyword( 4 , " call " );
44      setKeyword( 5 , " begin " );
45      setKeyword( 6 , " end " );
46      setKeyword( 7 , " if " );
47      setKeyword( 8 , " then " );
48      setKeyword( 9 , " while " );
49      setKeyword( 10 , " do " );
50      setKeyword( 11 , " odd " );
51      setKeyword( 12 , " + " );
52      setKeyword( 13 , " - " );
53      setKeyword( 14 , " * " );
54      setKeyword( 15 , " / " );
55      setKeyword( 16 , " > " );
56      setKeyword( 17 , " >= " );
57      setKeyword( 18 , " < " );
58      setKeyword( 19 , " <= " );
59      setKeyword( 20 , " = " );
60      setKeyword( 21 , " <> " );
61      setKeyword( 22 , " . " );
62      setKeyword( 23 , " ( " );
63      setKeyword( 24 , " ) " );
64      setKeyword( 25 , " , " );
65      setKeyword( 26 , " ; " );
66      setKeyword( 27 , " := " );
67 
68       /*
69       * work3.cpp
70        */
71      memset(N_ARRAY, 0 , sizeof (N_ARRAY));
72      memset(T_ARRAY, 0 , sizeof (T_ARRAY));
73      memset(F, 0 , sizeof (F));
74      memset(L, 0 , sizeof (F));
75      memset(PRECEDENCETABLE, 0 , sizeof (PRECEDENCETABLE));
76  }
work1.cpp
  1  /* **************************************************************\ * Author: Hu Wenbiao
  2   * Created Time: Wed 06 Oct 2010 09:29:56 AM CST
  3   * File Name: work1.cpp
  4   * Description: 处理源代码格式,将多余空格去掉,换行,跳格改成空格
  5   * 去掉注释。
  6  \************************************************************** */
  7  // *========================*Head File*========================*\\
  8 
  9  #include  " work.h "
 10  /* ----------------------*Global Variable*---------------------- */
 11 
 12  // *=======================*Main Program*=======================* //
 13 
 14  /*
 15   * 处理空格和注释
 16   */
 17  void  dealSourceCode(){
 18       bool  space = false ,multiply = false ,slash = false ,quote = false ;
 19       char  ch;
 20       int  slash_multiply = 0 ;
 21       while (scanf( " %c " , & ch) != EOF){
 22 
 23           if (ch == ' \\ ' ){ // 转义符
 24              printf( " \\ " );
 25              scanf( " %c " , & ch);
 26              printf( " %c " ,ch);
 27               continue ;
 28          }
 29 
 30           if (quote){ // 有引号
 31               // 有printf("\"")这种情况
 32               // 有printf("\\")这种情况
 33               // 有printf("")这种情况
 34 
 35               if (ch == ' \" ' ){ // 第三种情况
 36                  printf( " \ "" );
 37                  quote = false ;
 38                   continue ;
 39              }
 40 
 41                /*  处理前两种情况 */
 42               char  buf[ 10000 ];
 43               int  p = 0 ;
 44              buf[p ++ ] = ch;
 45               while (scanf( " %c " , & buf[p]) != EOF && (buf[p] != ' \" ' || (buf[p - 1 ] == ' \\ ' && (p == 1 || buf[p - 2 ] != ' \\ ' ))))p ++ ;
 46              buf[p + 1 ] = ' \0 ' ;
 47              printf( " %s " ,buf);
 48              quote = false ;
 49               continue ;
 50          }
 51 
 52           if (ch == '  ' || ch == ' \n ' || ch == ' \t ' ){ // 空格处理
 53               if ( ! space){
 54                  printf( "  " );
 55                  space = true ;
 56              }
 57               while (scanf( " %c " , & ch) != EOF && (ch == '  ' || ch == ' \n ' || ch == ' \t ' ));
 58          }
 59 
 60           if (ch == ' / ' ){ // 有可能是注释,注释处理
 61              scanf( " %c " , & ch);
 62 
 63               if (ch == ' / ' ){ // 单行注释
 64                   while (scanf( " %c " , & ch) != EOF && ch != ' \n ' );
 65              }
 66               else  if (ch == ' * ' ){ // 多行注释
 67                  slash_multiply = 1 ;
 68                  slash = multiply = false ;
 69                   while (slash_multiply){
 70                       if (scanf( " %c " , & ch) == EOF) break ; // 输入源文件语法错误
 71                       if (ch == ' / ' ){
 72                           if (multiply){
 73                              slash_multiply -- ;
 74                              multiply = slash = false ;
 75                          }
 76                           else
 77                            slash = true ;
 78                      }
 79                       else  if (ch == ' * ' ){
 80                           if (slash){
 81                              slash_multiply ++ ;
 82                              multiply = slash = false ;
 83                          }
 84                           else
 85                            multiply = true ;
 86                      }
 87                  }
 88              }
 89               else { // 不是注释
 90                  printf( " / " );
 91                   if (ch == '  ' || ch == ' \n ' || ch == ' \t ' )
 92                    space = true ;
 93                  printf( " %c " ,ch);
 94              }
 95          }
 96           else  if (ch == ' \" ' ){ // 发现第一个引号"\""
 97              printf( " \ "" );
 98              quote = true ;
 99          }
100           else { // 普通字符
101              printf( " %c " ,ch);
102              space = false ;
103          }
104      }
105  }
106  /*
107  int main(){
108      freopen("input.txt","r",stdin);
109      freopen("output.txt","w",stdout);
110      dealSourceCode();
111      return 0;
112  }
113  */
work2.cpp
/* **************************************************************\
 *Author:Hu Wenbiao
 *Created Time: Mon 15 Nov 2010 07:09:54 PM CST
 *File Name: work2.cpp
 *Description:词法分析器
\**************************************************************
*/
// *========================*Head File*========================*\\

#include
" work.h "
/* ----------------------*Global Variable*---------------------- */

KEYWORD_NODE KEYWORD[
30 ];
// *=======================*Main Program*=======================* //

bool  isLetter( char  ch){ // 判断是否是字母
     return  (ch >= ' a ' && ch <= ' z ' ) || (ch >= ' A ' && ch <= ' Z ' ) || (ch >= ' 0 ' && ch <= ' 9 ' );
}

bool  isNumber( char  ch){ // 判断是否是数字
     return  ch >= ' 0 ' && ch <= ' 9 ' ;
}

/*
 *判断是否是关键字,是则返回编码,否则返回28(标识符)
 
*/
int  getKeywordId( char *  str, int  s, int  t){
    
int  i,p;
    
for (i = 0 ;i < 12 ;i ++ ){
        p
= 0 ;
        
while  (KEYWORD[i].val[p]  &&  s + p <= &&  
                    KEYWORD[i].val[p]
== str[s + p]){
            p
++ ;
        }

        
if (KEYWORD[i].val[p] == ' \0 '  &&  s + p > t)
          
return  i;
    }
    
return  28 ; // id
}

/*
 *判断是否是分隔符或操作符,是则返回编码,否则返回0(Error)
 
*/
int  getSepOrOprId( char *  str, int  s, int  t){
    
int  i,p;
    
for (i = 12 ;i < 28 ;i ++ ){
        p
= 0 ;
        
while  (KEYWORD[i].val[p]  &&  s <= &&  
                    KEYWORD[i].val[p]
== str[s]){
            p
++ ,s ++ ;
        }

        
if (KEYWORD[i].val[p] == ' \0 '  &&  s > t)
          
return  i;
    }
    
return  0 ; // Error
}

/*
 * 按要求的格式输出
 
*/
void  printOut( int  id, char *  str, int  s, int  t){
    printf(
" %d:  " ,id);
    
for (;s <= t;s ++ )
      printf(
" %c " ,str[s]);
    printf(
" \n " );
}

/*
 * 是否是分隔符或操作符组成元素
 
*/
bool  isSepOrOpr( char  ch){
    
return  ch == ' + ' || ch == ' - ' || ch == ' * ' || ch == ' / ' || ch == ' > ' || ch == ' < ' || ch == ' = '
        
|| ch == ' . ' || ch == ' ( ' || ch == ' ) ' || ch == ' , ' || ch == ' ; ' || ch == ' : ' ;
}

/*
 * 对字符串str进行分析
 
*/
void  dealMorphology( char *  str){
    
int  p = 0 ,s,t;
    
while (str[p]){
        s
= t = p;
        
if (isNumber(str[p])){ // 整型
             while (str[p] && isNumber(str[p])) p ++ ;
            t
= p - 1 ;
            
if (isLetter(str[p])){ // 整型中有字母,错误
                printOut( 0 ,str,s,t);
            }
            
else { // 整型
                printOut( 29 ,str,s,t);
            }
        }
        
else  if (isLetter(str[p])){ // 标识符
             while (str[p] && (isLetter(str[p]) || isNumber(str[p]))) p ++ ;
            t
= p - 1 ;
            printOut(getKeywordId(str,s,t),str,s,t);
        }
        
else  if (isSepOrOpr(str[p])){ // 分隔符或操作符
             while (str[p]  &&  isSepOrOpr(str[p])) p ++ ;
            t
= p - 1 ;
            printOut(getSepOrOprId(str,s,t),str,s,t);
        }
        
else  if (s == t && str[s] == ' \n ' ){
            p
++ ;
            
continue ;
        }
        
else {
            printf(
" ERROR:\n " );
            p
++ ;
        }
    }
}

/*
 * 将dealSourceCode()处理后代码按空格进行分成若干字符串进行分别处理
 
*/
void  morphologyAnalysis(){
    
char  str[ 1000 ];  int  p;  bool  flag = true ;
    
while (flag){
        p
= 0 ;
        
while ((flag = (scanf( " %c " , & str[p]) != EOF)) && str[p] != '  ' ) p ++ ;
        str[p]
= 0 ;
        dealMorphology(str);
    }
}
work3.cpp
  1  /* **************************************************************\
  2   *Author:Hu Wenbiao
  3   *Created Time: Tue 16 Nov 2010 05:11:20 PM CST
  4   *File Name: work3.cpp
  5   *Description:算符优先文法
  6   * 1.非终结符和终结符的编号(id)都是它们在数组中的下标
  7   * 2.算法只能处理单字符的非终结符和终结符(大写字母为非终结符,
  8   * 其他为终结符)
  9   * 3.处理的表达式必须含有:=且其左边不能含有运算符,否则会被作为
 10   * 标识符的一部分处理
 11   * 4.表达式的标识符可以是字符串如:aa=bb+cc+dd*eef
 12   * 5.处理表达式时先将标识符转化为i(因为文法中只用i表示标识符),
 13   * 标识符的名称在NAME中记录,另外产生的中间标识符(如T1、E2)
 14   * 的名称也在NAME中记录,名称的id为其下标,NAME[0]记录等号“:=”
 15   * 左边的那个标识符,对于其他的标识符若id为0表示出错
 16  \************************************************************** */
 17  // *========================*Head File*========================*\\
 18 
 19  #include < stack >
 20  #include " work.h "
 21 
 22  /* ----------------------*Global Variable*---------------------- */
 23 
 24  N_NODE N_ARRAY[ 30 ]; // 非终端符数组(下标从1开始)
 25  char  T_ARRAY[ 30 ]; // 终端符数组(下标从1开始)
 26  bool  F[ 30 ][ 30 ],L[ 30 ][ 30 ]; // F[i][j]表示id为j的终结符是否属于
 27                           // id为i的非终结符的FIRSTVT,L相同。
 28  stack < pair < int , int >  >  S; // 用于求FIRSTVT和LASTVT
 29  char  PRECEDENCETABLE[ 30 ][ 30 ]; // 算符优先关系表
 30  char  NAME[ 100 ][ 10 ]; // 用来存放标识符名称,NAME[i]表示id为i的标识符
 31  int  name_foot[ 100 ]; // 分配中间标识符的下标,如T1中的1
 32  // *=======================*Main Program*=======================* //
 33 
 34  int  getTnodeId( char  ch){ // 返回终端符编码(下标),不存在返回0
 35       int  p = 1 ;
 36       while (T_ARRAY[p] && T_ARRAY[p] != ch) p ++ ;
 37       if (T_ARRAY[p])
 38           return  p;
 39       else
 40           return  0 ;
 41  }
 42 
 43  int  getNnodeId( char  ch){ // 返回非终端符编码(下标),不存在返回0
 44       int  pos = 1 ;
 45       while (N_ARRAY[pos].val  &&  N_ARRAY[pos].val != ch) pos ++ ;
 46       if (N_ARRAY[pos].val)
 47         return  pos;
 48       else
 49         return  0 ;
 50  }
 51 
 52  int  getNameId( char *  str, int  s, int  t){ // 给str[s]~str[t]分配位置,并返回id
 53       int  ptr = 0 ;
 54       while (NAME[ptr][ 0 ])ptr ++ ;
 55 
 56       for ( int  i = 0 ;s + i <= t;i ++ )
 57        NAME[ptr][i] = str[s + i];
 58 
 59       return  ptr;
 60  }
 61 
 62  int  getNameId( char  ch){ // 同上,重载
 63      name_foot[ch] ++ ;
 64       int  ptr = 0 ;
 65       while (NAME[ptr][ 0 ])ptr ++ ;
 66 
 67      NAME[ptr][ 0 ] = ch;
 68      NAME[ptr][ 1 ] = char (name_foot[ch] + ' 0 ' );
 69 
 70       return  ptr;
 71  }
 72 
 73  void  insertN_ARRAY( char  val, char *  str, int  s, int  t){ // 增加非终结符
 74       int  pos = 1 ;
 75       while (N_ARRAY[pos].val && N_ARRAY[pos].val != val) pos ++ ;
 76      N_ARRAY[pos].val = val;
 77       int  cnt = N_ARRAY[pos].cnt,p = 0 ;
 78       for (;s <= t;p ++ ,s ++ ){
 79          N_ARRAY[pos].ARR[cnt][p] = str[s];
 80      }
 81      N_ARRAY[pos].cnt ++ ;
 82  }
 83 
 84  void  insertT_ARRAY( char  ch){ // 增加终结符
 85       int  p = 1 ;
 86       while (T_ARRAY[p]) p ++ ;
 87      T_ARRAY[p] = ch;
 88  }
 89 
 90  bool  isNnode( char  ch){ // 判断是否是非终结符
 91       return  ch >= ' A ' && ch <= ' Z ' ;
 92  }
 93 
 94  /*
 95   * 求解所有非终结符的FIRSTVT
 96   */
 97 
 98  void  getFIRSTVT(){
 99      pair < int , int >  cur; // cur.first是非终结符的id,cur.second是终结符的id
100       int  nr_Nnode = 1 ;
101       while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ; // 其实nr_Nnode=(nr of Nnode)+1
102       for ( int  i = 1 ;i < nr_Nnode;i ++ ){ // 每个非终结符
103           for ( int  j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 每个产生式
104               if ( ! isNnode(N_ARRAY[i].ARR[j][ 0 ])){ // N_ARRAY[i].ARR[j][0]是终结符
105                   int  id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ 0 ]);
106                   if (F[i][id_Tnode]) continue ;
107                  F[i][id_Tnode] = true ;
108                  S.push(pair < int , int > (i,id_Tnode));
109              }
110               // N_ARRAY[i].ARR[j][1]是终结符
111               else  if (N_ARRAY[i].ARR[j][ 1 &&  ! isNnode(N_ARRAY[i].ARR[j][ 1 ])){
112                   int  id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ 1 ]);
113                   if (F[i][id_Tnode]) continue ;
114                  F[i][id_Tnode] = true ;
115                  S.push(pair < int , int > (i,id_Tnode));
116              }
117          }
118      }
119       while ( ! S.empty()){
120          cur = S.top(),S.pop();
121           char  curNnodeVal = N_ARRAY[cur.first].val;
122 
123           for ( int  i = 1 ;i < nr_Nnode;i ++ ){
124               if (F[i][cur.second]) continue ; // cur.second已经属于FIRSTVT(i)
125               for ( int  j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 查找哪个产生式右边以curNnodeVal为首
126                   if (N_ARRAY[i].ARR[j][ 0 ] == curNnodeVal){
127                      F[i][cur.second] = true ;
128                      S.push(pair < int , int > (i,cur.second));
129                       break ;
130                  }
131              }
132          }
133      }
134       /* 输出FIRSTVT */
135       for ( int  i = 1 ;i < nr_Nnode;i ++ ){
136           for ( int  j = 1 ;j < 30 ;j ++ ){
137               if (F[i][j]){
138                  printf( " FIRSTVT(%c): { " ,N_ARRAY[i].val);
139                   while (j < 30 ){
140                       if (F[i][j])
141                        printf( " %c  " ,T_ARRAY[j]);
142                      j ++ ;
143                  }
144                  printf( " }\n " );
145              }
146          }
147      }
148      printf( " \n " );
149       /**/
150  }
151 
152  /*
153   * 求解所有非终结符的LASTVT
154   */
155 
156  void  getLASTVT(){
157      pair < int , int >  cur;
158       int  nr_Nnode = 1 ;
159       while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ;
160       for ( int  i = 1 ;i < nr_Nnode;i ++ ){
161           for ( int  j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
162               int  ptr = 0 ;
163               while (N_ARRAY[i].ARR[j][ptr]) ptr ++ ;
164              ptr -- ;
165               if ( ! isNnode(N_ARRAY[i].ARR[j][ptr])){
166                   int  id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ptr]);
167                   if (L[i][id_Tnode]) continue ;
168                  L[i][id_Tnode] = true ;
169                  S.push(pair < int , int > (i,id_Tnode));
170              }
171               else  if (ptr > 0 &&! isNnode(N_ARRAY[i].ARR[j][ptr - 1 ])){
172                   int  id_Tnode = getTnodeId(N_ARRAY[i].ARR[j][ptr - 1 ]);
173                   if (L[i][id_Tnode]) continue ;
174                  L[i][id_Tnode] = true ;
175                  S.push(pair < int , int > (i,id_Tnode));
176              }
177          }
178      }
179       while ( ! S.empty()){
180          cur = S.top(),S.pop();
181           char  curNnodeVal = N_ARRAY[cur.first].val;
182 
183           for ( int  i = 1 ;i < nr_Nnode;i ++ ){
184               for ( int  j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
185                   int  ptr = 0 ;
186                   while (N_ARRAY[i].ARR[j][ptr]) ptr ++ ;
187                  ptr -- ;
188                   if (N_ARRAY[i].ARR[j][ptr] == curNnodeVal  &&
189                           ! L[i][cur.second]){
190                      L[i][cur.second] = true ;
191                      S.push(pair < int , int > (i,cur.second));
192                       break ;
193                  }
194              }
195          }
196      }
197       /* 输出LASTVT */
198       for ( int  i = 1 ;i < nr_Nnode;i ++ ){
199           for ( int  j = 1 ;j < 30 ;j ++ ){
200               if (L[i][j]){
201                  printf( " LASTVT(%c): { " ,N_ARRAY[i].val);
202                   while (j < 30 ){
203                       if (L[i][j])
204                        printf( " %c  " ,T_ARRAY[j]);
205                      j ++ ;
206                  }
207                  printf( " }\n " );
208              }
209          }
210      }
211      printf( " \n " );
212       /**/
213  }
214 
215  /*
216   * 求算符优先表
217   */
218 
219  void  getPrecedenceTable(){
220       int  nr_Nnode = 1 ,nr_Tnode = 1 ;
221       while (N_ARRAY[nr_Nnode].val) nr_Nnode ++ ;
222       while (T_ARRAY[nr_Tnode]) nr_Tnode ++ ;
223 
224       /* *关于#的比较* */
225       int  id_sharp = getTnodeId( ' # ' );
226       for ( int  j = 1 ;j < nr_Tnode;j ++ ){
227           if (F[ 1 ][j]){
228              PRECEDENCETABLE[id_sharp][j] = ' < ' ;
229          }
230           if (L[ 1 ][j]){
231              PRECEDENCETABLE[j][id_sharp] = ' > ' ;
232          }
233      }
234 
235       /* ************* */
236 
237       for ( int  i = 1 ;i < nr_Nnode;i ++ ){ // 每个非终结符
238           for ( int  j = 0 ;j < N_ARRAY[i].cnt;j ++ ){ // 每个产生式
239               int  tail = 0 ;
240               while (N_ARRAY[i].ARR[j][tail]) tail ++ ;
241              tail -- ; // 最后一位(非零)
242               for ( int  p = 0 ;p < tail;p ++ ){
243                   // tt
244                   if ( ! isNnode(N_ARRAY[i].ARR[j][p])  &&  
245                               ! isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
246                       int  id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
247                       int  id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
248                       if (PRECEDENCETABLE[id1][id2]){
249                          printf( " ERROR:不是算符优先文法! " );
250                          exit(EXIT_FAILURE);
251                      }
252                      PRECEDENCETABLE[id1][id2] = ' = ' ;
253                  }
254                   // tNt
255                   if (p <= tail - 2 &&! isNnode(N_ARRAY[i].ARR[j][p]) &&
256                              isNnode(N_ARRAY[i].ARR[j][p + 1 ]) &&
257                               ! isNnode(N_ARRAY[i].ARR[j][p + 2 ])){
258                       int  id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
259                       int  id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 2 ]);
260                       if (PRECEDENCETABLE[id1][id2]){
261                          printf( " ERROR:不是算符优先文法! " );
262                          exit(EXIT_FAILURE);
263                      }
264                      PRECEDENCETABLE[id1][id2] = ' = ' ;
265                  }
266                   // tN
267                   if ( ! isNnode(N_ARRAY[i].ARR[j][p])  &&
268                              isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
269                       int  id1 = getTnodeId(N_ARRAY[i].ARR[j][p]);
270                       int  id_Nnode = getNnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
271                       int  id2 = 1 ;
272                       while (T_ARRAY[id2]){
273                           if (F[id_Nnode][id2]){
274                               if (PRECEDENCETABLE[id1][id2]){
275                                  printf( " ERROR:不是算符优先文法! " );
276                                  exit(EXIT_FAILURE);
277                              }
278                              PRECEDENCETABLE[id1][id2] = ' < ' ;
279                          }
280                          id2  ++ ;
281                      }
282                  }
283                   // Nt
284                   if (isNnode(N_ARRAY[i].ARR[j][p])  &&
285                                   ! isNnode(N_ARRAY[i].ARR[j][p + 1 ])){
286                       int  id_Nnode = getNnodeId(N_ARRAY[i].ARR[j][p]);
287                       int  id2 = getTnodeId(N_ARRAY[i].ARR[j][p + 1 ]);
288                       int  id1 = 1 ;
289                       while (T_ARRAY[id1]){
290                           if (L[id_Nnode][id1]){
291                               if (PRECEDENCETABLE[id1][id2]){
292                                  printf( " ERROR:不是算符优先方法! " );
293                                  exit(EXIT_FAILURE);
294                              }
295                              PRECEDENCETABLE[id1][id2] = ' > ' ;
296                          }
297                          id1 ++ ;
298                      }
299                  }
300              }
301          }
302      }
303       ////// 输出优先表 ////// //
304      cout << "    " ;
305       for ( int  i = 1 ;i < nr_Tnode;i ++ ){
306          cout << T_ARRAY[i] << "  " ;
307      }
308      cout << endl;
309       for ( int  i = 1 ;i < nr_Tnode;i ++ ){
310          cout << T_ARRAY[i] << "  " ;
311           for ( int  j = 1 ;j < nr_Tnode;j ++ ){
312               if (PRECEDENCETABLE[i][j])
313                cout << PRECEDENCETABLE[i][j] << "  " ;
314               else
315                cout << "    " ;
316          }
317          cout << endl;
318      }
319      cout << endl;
320       ///////////////////// /
321  }
322 
323  /*
324   * 比较ARR[s]~ARR[t]中的id和str中的符号是否匹配
325   * 其中非终结符的id是取负值的,比较时也不比较非
326   * 终结符是否相同,只要求终结符相同,非终结符相
327   * 对应就返回true
328   */
329 
330  bool  cmpIdNodeVal(pair < int , int >*  ARR, int  s, int  t, char *  str){
331       int  ptr = 0 ,id;
332       while (s <= &&  str[ptr]){
333           if (isNnode(str[ptr])){ // 非终结符
334               if (ARR[s].first > 0 )
335                 return  false ;
336          }
337           else  if (ARR[s].first != getTnodeId(str[ptr]))
338             return  false ;
339          ptr ++ ;
340          s ++ ;
341      }
342       if (s <= ||  str[ptr])
343         return  false ;
344       return  true ;
345  }
346 
347  /*
348   * 将STACK[s]~STACK[t]归约,返回归约后的非终结符的值,
349   * 分配并由name返回非终结符的名称id
350   */
351 
352  char  reduction(pair < int , int >*  STACK, int  s, int  t, int &  name){
353       int  i = 1 ;
354       while (N_ARRAY[i].val){
355           for ( int  j = 0 ;j < N_ARRAY[i].cnt;j ++ ){
356               if (cmpIdNodeVal(STACK,s,t,N_ARRAY[i].ARR[j])){ // 查找成功
357 
358 
359                   /// 输出 ///
360 
361                   if (s == t && STACK[s].first > 0 ){ //  1
362                      name = STACK[s].second;
363                  }
364 
365                   if (s + 1 == t){ //  2
366                          name = getNameId(N_ARRAY[i].val);
367                       if (STACK[s].first > 0 ){
368                          printf( " (%c,_,%s,%s)\n " ,
369                                      T_ARRAY[STACK[s].first],NAME[STACK[t].second],NAME[name]);
370                      }
371                       else {
372                          printf( " (%c,%s,_,%s)\n " ,
373                                      T_ARRAY[STACK[t].first],NAME[STACK[s].second],NAME[name]);
374                      }
375                  }
376                   if (s + 2 == t){ //  3
377                       if (STACK[s].first > 0 && STACK[t].first > 0 ){ // (T)这种情况
378                          name = STACK[s + 1 ].second;
379                      }
380                       else {
381                          name = getNameId(N_ARRAY[i].val);
382                          printf( " (%c,%s,%s,%s)\n " ,T_ARRAY[STACK[s + 1 ].first],
383                                  NAME[STACK[s].second],NAME[STACK[t].second],NAME[name]);
384                      }
385                  }
386 
387                   ///////// /
388 
389                   return  N_ARRAY[i].val;
390              }
391          }
392          i ++ ;
393      }
394       return  0 ;
395  }
396 
397  /*
398   * 核心函数,处理传入的单句表达式,要求表达式必须为
399   * abc:=x*y+zuv 的形式,即必须有:=号且其左边不能有运
400   * 算符,否则会被当作标识符的一部分处理
401   */
402 
403  void  operatorPrecedenceParser( char *  str0){
404       /// 将空格去掉 ///
405       int  s = 0 ,t = 0 ,p;
406       while (str0[t]){
407           if (str0[t] != '  ' ){
408              str0[s] = str0[t];
409              s ++ ;
410          }
411          t ++ ;
412      }
413      str0[s] = 0 ;
414 
415       /// 将str0转换成str,由文法符号表示 ///
416       char  str[ 1000 ];
417       int  str_name[ 1000 ]; // str_name[i]是str[i]的名称,当str[i]为操作符时无意义
418 
419      memset(NAME, 0 , sizeof (NAME));
420      memset(name_foot, 0 , sizeof (name_foot));
421 
422      s = 0 ;
423       while (str0[s] && str0[s] != ' : ' )s ++ ;
424       if (str0[s] == 0 ){
425          printf( " ERROR:表达式不合法\n " );
426           return ;
427      }
428      getNameId(str0, 0 ,s - 1 ); // 放在NAME[0],在下面进行归约时标识符id为0时表示出错
429      s += 2 ; //  :=右边首字符
430      p = 0 ;
431       while (str0[s]){
432           if (isLetter(str0[s])){ // 标识符
433              t = s;
434               while (str0[t] && isLetter(str0[t]))t ++ ;
435              str[p] = ' i ' ;
436              str_name[p] = getNameId(str0,s,t - 1 );
437              s = t,p ++ ;
438          }
439           else { // 操作符
440              str[p] = str0[s];
441              s ++ ,p ++ ;
442          }
443      }
444      str[p] = ' # ' ; // 结束符
445      str[p + 1 ] = 0 ;
446       //////////// //
447      
448      pair < int , int >  STACK[ 1000 ]; // STACK[i].first保存id,正数是Tnode,负数是Nnode
449                                 // STACK[i].second保存标识符id 
450       int  k = 0 ,j;STACK[k].first = getTnodeId( ' # ' ); // STACK[k]栈顶
451      p = 0 ; // str[p]当前字符
452       int  q,cid;
453 
454       while (str[p]){
455          cid = getTnodeId(str[p]); // 当前字符id
456 
457           if (STACK[k].first > 0 ) j = k;
458           else  j = k - 1 ;
459 
460           while (PRECEDENCETABLE[STACK[j].first][cid] == ' > ' ){
461               do {
462                  q = STACK[j].first;
463                  j = STACK[j - 1 ].first > 0 ? j - 1 :j - 2 ;
464              } while (PRECEDENCETABLE[STACK[j].first][q] == ' = ' );
465 
466               int  tmp_name = 0 ;
467               char  tmp = reduction(STACK,j + 1 ,k,tmp_name); // 归约
468              k = j + 1 ;
469              STACK[k].first =- getNnodeId(tmp);
470               if (tmp_name)
471                STACK[k].second = tmp_name;
472               else  //  name为0表示错误
473                printf( " ERROR:tmp_name,when reduction " );
474          }
475           if (PRECEDENCETABLE[STACK[j].first][cid] == ' < '  ||
476                      PRECEDENCETABLE[STACK[j].first][cid] == ' = ' ){
477              k ++ ;
478              STACK[k].first = cid,STACK[k].second = str_name[p];
479              p ++ ;
480          }
481           else {
482               if (str[p] == ' # ' && j == 0 ){
483 
484                   // 给:=左边的符号赋值
485                  printf( " (:=,%s,_,%s)\n " ,NAME[STACK[ 1 ].second],NAME[ 0 ]);
486 
487                  printf( " Done!\n " );
488                   return ;
489              }
490               else {
491                  printf( " ERROR:归约时出错! " );
492                  exit( - 1 );
493              }
494          }
495      }
496      
497  }
498 
499  /*
500   * 读入文法
501   */
502 
503  void  readGrammar(){
504       char  str[ 30 ];
505      
506       while (scanf( " %[^\n]%*c " ,str) != EOF){
507           /// 将空格去掉 ///
508           int  s = 0 ,t = 0 ;
509           while (str[t]){
510               if (str[t] != '  ' ){
511                  str[s] = str[t];
512                  s ++ ;
513              }
514              t ++ ;
515          }
516          str[s] = 0 ;
517           //////////// //
518 
519           if (str[ 0 ] < ' A ' || str[ 0 ] > ' Z ' ){ // 检查首字母是否大写
520              printf( " ERROR:首字母不是非终结符\n " );
521               continue ;
522          }
523           int  p = 0 ;
524           while (str[p] && (str[p] != ' - ' || str[p + 1 ] != ' > ' )) p ++ ; // 检查是否有符号"->"
525           if ( ! str[p]){
526              printf( " ERROR:不是产生式\n " );
527               continue ;
528          }
529          p += 2 ;
530           /// 找终结符 ///
531          t = p;
532           while (str[t]){
533               if ( ! isNnode(str[t]) && str[t] != ' | ' )
534                insertT_ARRAY(str[t]);
535              t ++ ;
536          }
537           //////////// //
538 
539           /// 找产生式 ///
540           while (str[p]){
541              s = t = p; 
542               while (str[p] && str[p] != ' | ' ) p ++ ;
543               if (str[p]){
544                  t = p - 1 ,p ++ ;
545              }
546               else
547                  t = p;
548 
549              insertN_ARRAY(str[ 0 ],str,s,t);
550          }
551           //////////// //
552      }
553      insertT_ARRAY( ' # ' ); // 加入终结符'#'
554  }
555 
556  /*
557   * 算符优先文法主函数
558   */
559 
560  void  dealOperatorPrecedenceGrammar(){
561      freopen( " input31 " , " r " ,stdin);
562      freopen( " output3 " , " w " ,stdout);
563      readGrammar();
564      getFIRSTVT();
565      getLASTVT();
566      getPrecedenceTable();
567 
568      freopen( " input32 " , " r " ,stdin);
569       char  str[ 100 ];
570       while (scanf( " %[^\n]%*c " ,str) != EOF){
571          operatorPrecedenceParser(str);
572      }
573  }

 

 

work.cpp
 1  /* **************************************************************\
 2   *Author:Hu Wenbiao
 3   *Created Time: Mon 15 Nov 2010 09:58:46 PM CST
 4   *File Name: work.cpp
 5   *Description:主函数
 6  \************************************************************** */
 7  // *========================*Head File*========================*\\
 8 
 9  #include " work.h "
10  /* ----------------------*Global Variable*---------------------- */
11 
12  // *=======================*Main Program*=======================* //
13 
14  int  main(){
15      init();
16      freopen( " input1 " , " r " ,stdin);
17      freopen( " output1 " , " w " ,stdout);
18      dealSourceCode();
19      freopen( " output1 " , " r " ,stdin);
20      freopen( " output2 " , " w " ,stdout);
21      morphologyAnalysis();
22 
23      dealOperatorPrecedenceGrammar(); // 输入的设置在该函数中
24  }


 

 


 

 

你可能感兴趣的:(编译原理)