Skip to content

easyforgood/Mooc_complier

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 

Repository files navigation

Mooc_complier

保健哥Mooc上的课程 具体戳:Mooc_编译原理_华保健

这里是我写的Homework的源代码欢迎大家交流指正

邮箱:siplexy.pi@outlook.com

###Homework1

####一、课程总结 这一节主要是介绍一下编译器的构成。 在我看来编译器是非常模块化的东西。

最简单的编译器由 语法分析 -> 词法分析 -> 语义分析 -> 代码生成

但编译器的工作远不止此,为了提高代码运行的效率和质量,后面好需要做一系列的优化,后期处理。

正规化、控制流分析、SSA等等等

这一节主要的工作是 简单了解一下一个编译器的工作

我们把一个简单程序转换成了一个简单的伪汇编

语法:

  • 整形常量 int

  • 加运算 +

可用汇编代码:

  • push a

  • add

一个简单的实例是:

计算: 2+3+4

对应的汇编代码就是

push 2
push 3
add
push 4
add

为了方便转换这个代码,我们用于语法树的形式表示:

            +
           / \
          +   4
         / \
        2   3

我们可以发现,通过后序遍历 (左右中)

就可以构造出整个 汇编代码了。

####二、作业解释:

常量折叠 Constant_folding: 是其中一种被很多现代编译器使用的编译器最优化技术,常量折叠是在编译时间简单化常量表达的一个过程。

对于上述例子2+3+4,就是生成汇编代码的时候,只需要一条

push 9

就可以了

  • List_reverse_print 实现
//TODO
void List_reverse_print (struct List_t *list)
{
  //TODO();
  if(list==NULL){
      return;
  }
  else{
      List_reverse_print(list->next);
  }
  switch(list->instr->kind){
      case STACK_ADD:
         printf("add\n");break;
      case STACK_PUSH:
         printf("push %d\n",((struct Stack_Push *)(list->instr))->i);
         break;
  }
  
}

这是逆序输出。所以是先遍历,再输出,利用递归的特性

  • compile() No Constant Folding
void compile (struct Exp_t *exp)
{
  switch (exp->kind){
  case EXP_INT:{
    struct Exp_Int *p = (struct Exp_Int *)exp;
    emit (Stack_Push_new (p->i));
    break;
  }
  case EXP_SUM:{
    //TODO()
    struct Exp_Sum *p=(struct Exp_Sum *)exp;
    compile(p->left);
    compile(p->right);
    emit(Stack_Add_new());  //if you dont want to use Constant folding
    break;
  }
  default:
    break;
  }
}
  • compile() Constant Folding
int pop(){
    struct Stack_Push * p=(struct Stack_Push *)(all->instr);
    all=all->next;
    return p->i;
}

void compile (struct Exp_t *exp)
{
  switch (exp->kind){
  case EXP_INT:{
    struct Exp_Int *p = (struct Exp_Int *)exp;
    emit (Stack_Push_new (p->i));
    break;
  }
  case EXP_SUM:{
    //TODO()
    struct Exp_Sum *p=(struct Exp_Sum *)exp;
    compile(p->left);
    compile(p->right);
    int a=pop();
    int b=pop();
    emit(Stack_Push_new(a+b));
    break;
  }
  default:
    break;
  }
}

这里附加了一个int pop()函数,用于弹出栈顶的元素。 相加计算结果之后再push

具体代码见:src/complier_bjhua_hw1.c

####三、秀截图

pic

pic

逆序输出意思是按照执行顺序输出!


###Homework2

####一、课程总结

本节课讲的是词法分析。

上节课我们知道了编译器是一个非常模块化的东西,是一个非常流水化的结构。

词法分析器是编译器中的第一个模块,他的输入主要就是以文件形式存在的字符流, 输出是可以被程序语言内部定义的词法单元,被称为记号流

这就是词法分析器的工作,将写好源代码的字符流转换成程序语言内部的记号流

例如: 一段程序是这样的

  if(x > = 3)
    todo()

切分成记号流

  IF LPRAREN IDINT(x) GTEQ INT(3)
    FUNC("todo")

类似这样。

(这里需要注意 回车"\n" "\r\n"和空格" "的存在)

实现这样的词法分析器主要有两种方式:

  • 手工构造: 通过 逐个读取字符进行手工判断

  • 自动构造:利用正则表达式进行判断

(作者注:这个地方有所质疑,没体会到有多大区别,可能用过flex才知道吧)

个人觉得都是 状态转移图这种思想和原理

分析一下作业的状态转移图:

规则:

  • 读取IF

  • 读取标识符

  • 读取整型数

pic

实际上是一个NFA。

还好比较简单,要是复杂了照着这个图这样写代码就很混乱了。

####二、代码分析:

上一张图已经说明了状态转移,实现代码如下:

这里可以直接用空格或者换行考虑进行字符截断,所以不需要考虑rollback,因为空格和换行肯定是没有意义的换成"("就不行了

//词法分析
void lexer(int ch){
    switch(state){
        case 0:
            //第一次输入,可以选择状态
            if (ch == 'i'){
                state=1;
            }
            else if (ch>='0' && ch <= '9'){
                state=2;
            }
            else if ((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||ch=='_'){
                state=3;
            }
            else{
                startPos++;
            }
            break;
        //上次输入为i,输入为空格说明是ID了直接输出,其他情况还需要进行判断
        case 1:
            if (ch == 'f'){
                state=4;
            }
            else if (ch == ' ' || ch == '\n'){
                printID();
            }
            else{
                state=3;
            }
            break;
        //数字。空格或回车直接截断输出
        case 2:
            if(ch == ' ' || ch == '\n'){
                printINT();
            }
            break;
        //标识符。同样直接截断
        case 3:
            if(ch == ' ' || ch =='\n'){
                printID();
            }
            break;
        //已经输入了if,如果截断了直接输出IF,省略state:5 ,否则跳入ID
        case 4:
            if (ch == ' ' || ch == '\n'){
                printIF();
            }
            else{
                state=3;
            }
            break;
        default:break;

    }
    //每次操作都对齐nowPos
    nowPos=ftell(fp);

}

####三、结果截图

测试文本:

pic

pic

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published