用户操作
[留言]  [发消息]  [加为好友] 
订阅我的博客
XML聚合    FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
eharry的公告
文章分类
存档

原创  编译实验报告 收藏


7:54 2006-3-16


试验报告:

主程序,cmplie.exe   源文件 cmplie.c

辅助程序  creatTree.exe viewTree.exe

pro.txt 是输入的“程序”文件,即要被编译的文件

pro.txt----------->(cmplie.exe)------->te.txt 和 四元式(在屏幕上)

te.txt-------->(creatTree.exe)--------->tree.xml

tree.xml------->(viewTree.exe)--------->可视化语法树

语法规则:


program->def_list
def_list->def_list defintion|defintion
defintion->type var_init kinds
var_use->id [simple_exp]*
type->int | bool
kinds-> = num ;| ( type var_use) { sentence_list } | ;
sentence_list->sentence_list sentence | sentence
sentence->expper | simple_exp;
expper->var_use = simple_exp;| phylum| call ;| if_stmt | while_stmt | return_stmt
phylum->{ sentence_list }
call->id (id_list)
e->else sentence_list | empty
if_stmt->if ( relop_exp ) sentence e
while_stmt->while ( relop_exp ) sentence
renturn_stmt->return simple_exp ;
id_list->var_use [,var_use]* | empty
simple_exp-> trem [addop term]*
term->term mulop factor | factor
factor->( simple_exp ) | var_use | num
relop_exp->simple_exp [relop simple_exp]+
mulop->* | \
addop -> + | -
relop->== | < | <= | > | >= | != | & | ! | |

类似c语言的规则,

系统主要构成:
  预处理程序(删除注释)+词法分析程序+LL2(语法分析)+基于自顶向下的语义分析+输出中间代码

核心算法:

模块化解释:
    预处理程序:
 代码:
  void clear()
  {
      FILE *fout,*fin;
      char t;
      fout=fopen("pro.txt","r");
      fin=fopen("te.txt","w");
      t=fgetc(fout);
      while(!feof(fout))   去处类似 // 之类的注释
      {
   
   if(t!='/') fprintf(fin,"%c",t);
   else
   {
       t=fgetc(fout);
       if(t!='/')
       {
    fprintf(fin,"%c",t);
    continue;
       }
       else
       {
          while(t!='\n') t=fgetc(fout);
       }
       fprintf(fin,"%c",t);
   }
   t=fgetc(fout);
      }
      fprintf(fin,"$");
      fclose(fout);
      fclose(fin);
  }
    词法分析程序:
 代码:
        采用token_first 和 token_second 两个结构体来保留两个字符,
  int accept()     为了满足LL2分析设计的具有提前读取的词法分析程序
  {      
      char *p;
        每次从文件读到token_second中,token_first的内容是token_second前一次的
        例如:文件里有 a b c d 四个词
        在同一状态下:
          状态     token_first    token_second
          1           NULL            a
          2            a              b
          3            b              c
          4            c              d
          5            d              NULL
        可以看出,token_second 总是走在 token_first 前
   p=token_second.content;
                                                         将上一次token_second 赋值给 token_first
   strcpy(token_first.content,token_second.content);
   token_first.lines=token_second.lines;
   token_first.type=token_second.type;
   token_first.value=token_second.value;
   
      *p='\0';
    if( ch1 == '$')
     return 1;

    charNoEmpty();

    token_second.lines=lines;
    token_second.value=0;
    if((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z'))         字符串处理
    {
     do{
      *p=ch1;
      p++;
      ch1=fgetc(input);
     }while(((ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z') || (ch1 >= '0' && ch1 <= '9') )) ;
     *p='\0';
     token_second.type=typeDef(token_second.content);              判断是 保留字 还是 标志符
     return 1;  
    }
    
    if(ch1 >= '0' && ch1 <= '9')                                         数字串处理
    {
     do{
      *p=ch1;
      p++;
      ch1=fgetc(input);
     }while(ch1 >= '0' && ch1 <= '9') ;
     *p='\0';
     token_second.type=SYM_num;
     token_second.value=changNum(token_second.content);
     return 1;
    }
    switch(ch1)                                                           界符 运算符的处理
    {
     case '>':   *p=ch1;
       p++;
       ch1=fgetc(input);
       if(ch1 == '=')
       {
        *p=ch1;
        p++;
        *p='\0';
        ch1=fgetc(input);
        token_second.type=SYM_MoreOrEqual; 
       }
       else
       {
        *p='\0';
        token_second.type=SYM_More;
       }
       break;  
     
     
     case '<':   *p=ch1;
       p++;
       ch1=fgetc(input);
       if(ch1 == '=')
       {
        *p=ch1;
        p++;
        *p='\0';
        ch1=fgetc(input);
        token_second.type=SYM_LessOrEqual;  
       }
       else
       {
        *p='\0';
        token_second.type=SYM_Less;
       }
       break;
     
     
     case '=':    *p=ch1;
       p++;
       ch1=fgetc(input);
       if(ch1 == '=')
       {
        *p=ch1;
        p++;
        *p='\0';
        ch1=fgetc(input);
        token_second.type=SYM_Equal;  
       }
       else
       {
        *p='\0';
        token_second.type=SYM_Evaluate; 
       }
       break;    
     
         
     case '!':    *p=ch1;
       p++;
       ch1=fgetc(input);
       if(ch1 == '=')
       {
        *p=ch1;
        p++;
        *p='\0';
        ch1=fgetc(input);
        token_second.type=SYM_NotEqual;  
       }
       else
       {
        *p='\0';
        token_second.type=SYM_Not; 
       }
       break;
     
     case '{':token_second.type=SYM_BigLeftBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '}':token_second.type=SYM_BigRightBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case ';':token_second.type=SYM_Semicolon;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case ',':token_second.type=SYM_Comma;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '+':token_second.type=SYM_Plus;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '-':token_second.type=SYM_Sub;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '*':token_second.type=SYM_Mul;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '/':token_second.type=SYM_Div;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '(':token_second.type=SYM_LeftBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case ')':token_second.type=SYM_RightBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '&':token_second.type=SYM_And;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '|':token_second.type=SYM_Or;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case '[':token_second.type=SYM_NormalLeftBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;
     case ']':token_second.type=SYM_NormalRightBracket;*p=ch1;p++;*p='\0';ch1=fgetc(input);break;

     case '$':break;
     default: error(1);break;
     }  
    return 1;
  }
 语法分析:
  代码:
   代码太长了,语法分析采用的是LL1和局部LL2的分析方法,自顶向下的递归调用方法编程.
   语法规则一:
    factor->( simple_exp ) | var_use | num
   代码一: 
    struct op factor()
    {
        struct op temp1,temp;
     switch(token_first.type)
     {
      case SYM_LeftBracket:
          accept();
          temp1=simple_exp();
          {
                temp.place=temp1.place;
          }
          if( token_first.type != SYM_RightBracket)
           error(1);
          accept();
          break;
      case SYM_id:  {
        temp.place=serch(token_first.content);
             }   
          accept();
          break;
      case SYM_num: {
        temp.place=fill_num(token_first.value);
             }
          accept();
          break;
      default: error(1);break;
     }
     return temp;
    }

    由于语义处理同语法处理,同时进行,所以factor函数由语法角度看来不太明确,修改上述代码,可得纯语法分析代码:
    void factor()
    {
     
     switch(token_first.type)
     {
      case SYM_LeftBracket:
          accept();
          simple_exp();
          if( token_first.type != SYM_RightBracket)
           error(1);
          accept();
          break;

      case SYM_id:   accept();
          break;

      case SYM_num:   accept();
          break;

      default:   error(1);break;
     }
    }
    对比明确的语法规则:factor->( simple_exp ) | var_use | num
                               
                      
      
    代码开篇分了三种情况,满足那一种条件,调用哪个函数;
   语法规则二:
    expper->var_use = simple_exp;| phylum| call ;| if_stmt | while_stmt | return_stmt

    特意调出这个在LL1文法中冲突的地方,由语法规则可知:var_use 和 call 的首字符中都有 id ,所以比较它们的
    第二个字符,代码中直接调用token_second来进行判断
   .......
   case SYM_id:
    if(token_second.type == SYM_Evaluate || token_second.type == SYM_NormalLeftBracket)
       {
       .......
         
       }
           else
           {
       .......
           }
                       break;
   .......
   
            由代码可以看出,在首字符都是ID的情况下,接下来判断token_second
语义分析:
 语义分析从动作行为上说,分为这几类:
          填表,查表,生成四元式,分配变量和四元式的等,每个行为举一个例子,
   表有几种:
   符号表 (均有基本类型构成)                操作:serch,fill,fill_num
   int num;
   char name[10];
   int type;       //类型(0表示num,1,int,2,bool,1,单个变量,2,数组,5,函数)
   int shuzu[3];   //维数,维长
   int place;
   

   四元式表      操作:getpos,emit
   int lop;                  struct pl
   struct pl e1;             int p;
   struct pl e2;    int offset;
   struct pl e;
                 serch:
   struct pl serch(char *str)              查找×str表示的字符串在符号表的位置
   {
    struct pl temp;
    int i=top-1;
    while(i>=0)
    {
     if(!strcmp(table[i].name,str))
     {
      temp.p=i;
      temp.offset=0;
      return temp;
     }
     i--;
    }
    temp.p=-1;
    return temp;
   }
  fill:
   struct pl fill(char *str)              将*str填入到符号表里,返回符号表的序号
   {
    struct pl temp;
    strcpy(table[top].name,str);
    top++;
    temp.p=top-1;
    temp.offset=0;
    return temp;
   }
  fill_num:
   struct pl fill_num(int num)            
   {
    struct pl temp;
       table[top].num=num;
    
    top++;
    temp.p=top-1;
    temp.offset=0;
    return temp;
   }
  getpos:
   int getpos()
   {
    return pos;
   }
  emit:
   int emit(int a,struct pl b,struct pl c,struct pl d)      纯粹的赋值
   {
    mid[pos].lop=a;
    mid[pos].e1=b;
    mid[pos].e2=c;
    mid[pos].e=d;
    pos++;
    return pos-1;
   }
  newTemp:
   struct pl newTemp(int type)                 生成新的临时变量
   {
    struct pl temp;
    end++;
    temp.p=end-1;
    temp.offset=0;
    return temp;
   }
  fenpei:
   void fenpei()
   {
    int i,j;
    i=pos*4;
    for(j=0; j < top; j++)
    {
     switch(table[j].type)
     {
      case 0:;
      case 1:table[j].place=i;i++;break;
      case 2:table[j].place=i;i+=2;break;
      case 12:table[j].place=i;
        if(table[j].shuzu[0] == 1)
         i+=table[j].shuzu[1];
        else
         i+=table[j].shuzu[1]*table[j].shuzu[2];
        break;
      case 5:table[j].place=i;i+=2;break;
     }
    }
    for(j=80; j < end; j++)
    {
     switch(table[j].type)
     {
      case 0:
      case 1:table[j].place=i;i++;break;
      case 2:table[j].place=i;i+=2;break;
      case 12:table[j].place=i;
        if(table[j].shuzu[0] == 1)
         i+=table[j].shuzu[1];
        else
         i+=table[j].shuzu[1]*table[j].shuzu[2];
        break;
     }
    }

   }
  所有的公共子函数看完了,下面是几个具体的语法分析夹杂语义分析的实例:
  1。先看数组变量的定义和引用
   定义:
    struct op var_init(struct op temp2)  //传入参数表示类型
    {
        struct op temp1;
     int i=1;
        {//语义
      temp1.place=fill(token_first.content);
      table[temp1.place.p].type=temp2.code;
        }
        accept();
     if(token_first.type == SYM_NormalLeftBracket)
     {
      table[temp1.place.p].type*=10;
      table[temp1.place.p].type+=2;
     }                                                     前面是普通的变量定义,后面while循环里面是关于数组的定义,
            涉及数组维数和每维的长度
     while(token_first.type == SYM_NormalLeftBracket)
     {
         accept();
         if( token_first.type != SYM_num)
       error(1);
      table[temp1.place.p].shuzu[1]++;
      i+=table[temp1.place.p].shuzu[1];
      table[temp1.place.p].shuzu[i]=token_first.value;
         accept();
     if( token_first.type != SYM_NormalRightBracket)
       error(1);
     accept();
     
        }
     
        return temp1;
    }
   引用:
    struct op var_use()
    {
        int i=1;
     
        struct op temp1;
        {//语义
      temp1.place=serch(token_first.content);
        }   
        accept();
     while(token_first.type == SYM_NormalLeftBracket)
     {
         i++;
         accept();
         if( token_first.type != SYM_num)
       error(1);
        
     temp1.place.offset=temp1.place.offset * table[temp1.place.p].shuzu[i+1];
      temp1.place.offset+=token_first.value;
      
        
      accept();
     if( token_first.type != SYM_NormalRightBracket)
       error(1);
     accept();       
        }
        return temp1;
    }
  2。if 语句的翻译
   struct op if_stmt()
   {
     struct op temp,temp1,temp2;
     struct pl pltemp;
     int m1,m2,m3;

    if(token_first.type == SYM_if)
    {
     
     accept();

     if( token_first.type != SYM_LeftBracket)
      error(1);
     
     accept();

     temp1=relop_exp();
     
     {//语义                                          产生两个跳转函数,分别跳到条件成立和不成立的两个地方去
      m1=emit(SYM_Jz,temp1.place,zero,zero);
      m2=emit(SYM_Jmp,zero,zero,zero);
     }
     if( token_first.type != SYM_RightBracket)
      error(1);
     accept();
     {//语义                                           重新给条件成立的跳转函数的四元式赋值
      pltemp.p=getpos();
      pltemp.offset=0;
      mid[m1].e=pltemp;
     }
     sentence_list();
     {//语义                                            跳过else 的范围
      m3=emit(SYM_Jmp,zero,zero,zero);
     }   
     {//语义                                            给条件不成立的跳转函数的四元式赋值
      pltemp.p=getpos();
      pltemp.offset=0;
      mid[m2].e=pltemp;
     }
     temp2=e();
     {//语义                                             给调处else的范围四元式赋值
         pltemp.p=getpos();
         pltemp.offset=0;
         mid[m3].e=pltemp;
     }   
     

    }
    else
    {
     error(1);
    }
    return temp;
   }
   /************************************/
   struct op e()
   {
       struct op temp;
       if( token_first.type == SYM_else)
    {
       
     accept();
       
        if( token_first.type == SYM_BigLeftBracket)
     {
      
      accept();

      sentence_list();

      if( token_first.type != SYM_BigRightBracket)
       error(1);
      accept();
     }
     else
     {
      error(1);
     }
       }
       return temp;
   }
  3.while语句的翻译
   struct op while_stmt()
   {
    struct op temp,temp1;
    struct pl pltemp;
    int m1,m2;
    if(token_first.type == SYM_while)
    {
     
     accept();


     if(token_first.type != SYM_LeftBracket)
      error(1);
     accept();
     {
         m1=getpos();                                 取得while开始的循环部分
     }   
     temp1=relop_exp();
     {//语义
      m2=getpos();
      pltemp.p=m2+2;
      pltemp.offset=0;
      emit(SYM_Jz,temp1.place,zero,pltemp);    产生跳转语句,分别对待条件
      m2=emit(SYM_Jmp,zero,zero,zero);
     }
     if(token_first.type != SYM_RightBracket)
      error(1);
     accept();
     sentence();
     {
      pltemp.p=m1;
      pltemp.offset=0;
      emit(SYM_Jmp,zero,zero,pltemp);          为了执行下个循环,跳转到while开始部分
     }
     {
      pltemp.p=getpos();
      pltemp.offset=0;
      mid[m2].e=pltemp;                        给条件为假是,调出while的四元式赋值
     }
    }
    else
    {
     error(1);
    }
    return temp;
    
   }
  语义分析在每个函数中都存在着,通过上面几个特殊的例子,可以更好的了解语义分析和语法分析。


系统实例:

int a[5];
int b=20;
int e=90;
bool c=1;
bool d=1;
int main() //jkjkjkdflk
{
 a[3]=b+2;
    b=b+2;  
 while( b > 9)
       {
  if(e>b)
  {
   c=0;
  }
  else
  {
   b=0;
  }
 }
  
}
生成::::::::::::::::::::::
地址   (四元式代码)
       操作码   量(1) (2)     (3)   均是地址表示        解释
0       18      168     0       167                     [167]=[168] b=20
4       18      170     0       169                     [169]=[170] e=90
8       18      173     0       171                     [171]=[173] c=1
12      18      176     0       174                     [174]=[176] d=1
16      18      167     0       183                     [183]=[167] [183]=b
20      18      183     0       184                                 [184]=b
24      18      178     0       185                                 [185]=2
28      11      184     185     184                                 [184]=b+2
32      18      184     0       165                      [165]=b+2   a[3]=b+2
36      18      167     0       186
40      18      186     0       187
44      18      179     0       188
48      11      187     188     187
52      18      187     0       167                                   b=b+2
56      18      167     0       189                       [189]=b
60      18      189     0       190                        [190]=b
64      18      190     0       191                          [191]=b
68      18      180     0       192                           [192]=[180]=9
72      18      192     0       193                            [193]=9
76      22      191     193     191                              比较大小
80      33      191     0       88                                 转移
84      32      0       0       152                                  两个方向,88(进入),152(跳过while)
88      18      169     0       194
92      18      194     0       195
96      18      195     0       196
100     18      167     0       197
104     18      197     0       198
108     22      196     198     196                          if函数判断
112     33      196     0       120                             成立(120)
116     32      0       0       136                              否定(136)
120     18      181     0       199
124     18      199     0       200
128     18      200     0       171
132     32      0       0       148
136     18      182     0       201
140     18      201     0       202
144     18      202     0       167
148     32      0       0       56                            while的最后跳转

符号表:
个数   内容             地址
0       0               152
1       0               153
2       0               154
3       0               155
4       0               156
5       0               157
6       0               158
7       0               159
8       0               160
9       0               161
10      a       12      162
11      b       1       167
12      20              168
13      e       1       169
14      90              170
15      c       2       171
16      1               173
17      d       2       174
18      1               176
19      main    1       177
20      2               178
21      2               179
22      9               180
23      0               181
24      0               182

临时变量表:
个数   内容             地址 
80      0               183
81      0               184
82      0               185
83      0               186
84      0               187
85      0               188
86      0               189
87      0               190
88      0               191
89      0               192
90      0               193
91      0               194
92      0               195
93      0               196
94      0               197
95      0               198
96      0               199
97      0               200
98      0               201
99      0               202

操作码表:
#define       SYM_int              1      
#define       SYM_bool             2        
#define       SYM_if               3        
#define       SYM_else             4        
#define       SYM_while            5
#define       SYM_do               6
#define       SYM_return           7     
#define       SYM_BigLeftBracket                8       
#define       SYM_BigRightBracket                9        
#define       SYM_Semicolon                10        
#define       SYM_Plus                11       
#define       SYM_Sub              12    
#define       SYM_Mul                13      
#define       SYM_Div              14      
#define       SYM_LeftBracket                15       
#define       SYM_RightBracket              16      
#define       SYM_Comma               17      
#define       SYM_Evaluate              18      
#define       SYM_Equal              19   
#define       SYM_Less             20    
#define       SYM_LessOrEqual               21     
#define       SYM_More                22       
#define       SYM_MoreOrEqual             23      
#define       SYM_NotEqual              24       
#define       SYM_Not              25
#define       SYM_And                26
#define       SYM_Or                27            
#define       SYM_num              28
#define       SYM_id               29
#define       SYM_NormalLeftBracket   30
#define       SYM_NormalRightBracket 31
#define       SYM_Jmp     32
#define       SYM_Jz     33
#define       SYM_Return                34
#define       SYM_Call     35


总结:
距离要求差语义分析错误,和bool函数的运算。


发表于 @ 2006年05月22日 23:45:00 | 评论( loading... ) | 编辑| 举报| 收藏

旧一篇:complie.h | 新一篇:lotus论坛

  • 发表评论
  • 评论内容:
  •  
Copyright © eharry
Powered by CSDN Blog