编译原理 C-Minus 代码生成(Flex / Bison)

C-Minus 源代码 代码生成

一、实现目标

  在前几篇文章中,我们已经实现了 C-Minus 语法的词法分析、语法分析及语义分析,这次我们将编写一个程序对使用类C语言书写的源代码翻译为中间代码/目标代码,并打印翻译结果。
  程序要能够检查源代码中可能包含的词法错误:

  • (1)最低要求2.1: 能够输出抽象语法树及四元式的中间代码,应至少包括以下代码类型:赋值语句、算术运算操作(加减乘除)、跳转语句、分支与循环语句
  • (2)其他要求2.2: 能够将中间代码的基础上,生成某类目标代码(汇编/MIPS)

二、实现过程

(一)内容综述

  对上述目标,本文实现的内容如下:

  1. 检查词法、语法、语义错误并输出
  2. 生成并输出抽象语法树
  3. 能够生成四元式中间代码,可处理的类型包括:赋值语句、算术运算操作(加减乘除)、跳转语句、分支与while循环语句、函数定义(参数声明、参数声明、函数体)、函数调用(函数传参、函数返回)
  4. 能够对中间代码进行优化,优化方式为局部优化,主要采用合并已知量、删除多余运算的方式,减少对常量和临时变量的复用
  5. 能够生成目标代码并在QtMips上运行,可处理的类型包括:read函数、write函数、main函数(程序入口)、赋值语句、算术运算操作(加减乘除)、跳转语句、分支与while循环语句、函数返回

(二)代码分析

  由于在代码中已经对各个函数功能、过程进行了详细的注释,因此在代码分析章节中会减少文字叙述。

1. 中间代码的表示

  在本文中,我采用线性中间代码双链表的存储方式,在语法分析结束后进行中间代码的生成。
  对单条中间代码可以将代码类型和操作数分别进行存储,数据结构定义如下:

typedef struct _OperandStru // 操作数
{
    enum
    {
        VARIABLE, // 变量 x
        TEMPVAR,  // 临时变量 t1
        LABLE,    // 标签 lable1
        CONSTANT, // 常数 #1
        ADDRESS,  // 取地址 &x
        VALUE,    // 读取地址的值 *x
        FUNC,     // 函数
    } kind;
    union {
        int tempvar; // 临时变量
        int lable;   // 标签
        int value;   // 常数的值
        char *name;  // 语义值,变量名称、函数名称
    } operand;
    int value;
} OperandStru, *Operand;

  对操作数进行存储时,需要区分操作数的类型;对于不同类型的中间代码,其操作数的数量也是不同的,因此使用union进行存储。同时为了实现对函数声明、函数调用语句的翻译,定义了函数参数列表的数据结构,在递归调用的翻译过程中存储所有的参数。

typedef struct _InterCodeStru // 中间代码
{
    // 代码类型
    enum
    {
        _LABLE,    // 定义标号
        _FUNCTION, // 定义函数
        _ASSIGN,   // =
        _ADD,      // +
        _SUB,      // -
        _MUL,      // *
        _DIV,      // /
        _GOTO,     // 无条件跳转
        _IFGOTO,   // 判断跳转
        _RETURN,   // 函数返回
        _ARG,      // 传实参
        _CALL,     // 函数调用
        _PARAM,    // 函数参数声明
        _READ,     // 从控制台读取x
        _WRITE,    // 向控制台打印x
        _NULL      // 空的
    } kind;
    // 操作数
    union {
        struct
        { // 赋值 取地址 函数调用等
            Operand left, right;
        } assign;
        struct
        { // 双目运算 + = * /
            Operand result, op1, op2;
        } binop;
        struct
        { // GOTO 和 IF...GOTO
            Operand lable, op1, op2;
            char *relop;
        } jump;
        // 函数声明、参数声明、标签、传实参、函数返回、读取x、打印x
        Operand var;
    } operands;
    struct _InterCodeStru *prev, *next;
} InterCodeStru, *InterCode;

// 函数参数列表
typedef struct _ArgListStru
{
    int num;
    Operand list[10];
} ArgListStru, *ArgList;

InterCode CodesHead, CodesTail; // 全局变量,线性IR双链表的首尾

   在中间代码中,我们需要声明很多临时变量和标签作为操作数,这里设置了全局变量用于存储生成的临时变量,同时为了进行中间代码优化,我将每个临时变量所表示的操作数进行存储

// 临时变量t1和标签lable1
int tempvar[100];
Operand temp_Operands[100];
int lables[100];
2. 中间代码生成与优化

   本次实验中我采用自顶向下遍历语法分析树的方式生成中间代码,减少了模块的耦合性。
   为了生成中间代码,我编写了许多中间函数,简化了分析过程

// 初始化双链表
void init_InterCode();
// 创建一个新的操作数
Operand new_Operand();
// 创建一个新的变量
Operand new_Variable(char *name);
// 创建一个新的常量
Operand new_Const(float value);
// 创建一条新的中间代码
InterCode new_Code();
// 创建一条lable声明的中间代码
InterCode new_lable_Code(Operand lable);
// 创建一条跳转语句的中间代码
InterCode new_goto_Code(Operand lable);
// 创建一条赋值的中间代码
InterCode new_assign_Code(Operand left, Operand right);
// 打印一条中间代码
void print_Code(InterCode code);
// 打印一个操作数
void print_Operand(Operand op);
// 打印一段中间代码
void print_Codes(InterCode codes);
// 获取链表的尾部
InterCode get_Tail(InterCode codes);
// 在链表末尾加上另一条链表
InterCode add_Codes(int num, ...);

   临时变量与新的标签生成方式如下:

Operand new_tempvar()
{
    int i;
    for (i = 0; i < 100; i++)
    {
        if (tempvar[i] == -1)
        {
            tempvar[i] = 1;
            break;
        }
    }
    if (i >= 100)
        return NULL;
    Operand result = new_Operand();
    result->kind = TEMPVAR;
    result->operand.tempvar = i + 1;
    temp_Operands[i] = result;
    return result;
}
Operand new_lable()
{
    int i;
    for (i = 0; i < 100; i++)
    {
        if (lables[i] == -1)
        {
            lables[i] = 1;
            break;
        }
    }
    if (i >= 100)
        return NULL;
    Operand result = new_Operand();
    result->kind = LABLE;
    result->operand.lable = i + 1;
    return result;
}

   同时为了减少对临时变量的重复声明,在翻译基本表达式、条件表达式以及一些语句时,进行变量表的遍历,对于存储相同值的临时变量直接使用即可,不再重复生成:

// 当Exp的翻译模式为INT、ID、MINUS Exp时,可以获取已经申明过的操作数
Operand get_Operand(tnode Exp)
{
    // INT
    if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "INT"))
    {
        return find_Const((int)((Exp->cld)[0]->value));
    }
    // ID
    else if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "ID"))
    {
        Operand variable = new_Variable((Exp->cld)[0]->content);
        return variable;
    }
    // MINUS Exp  (Exp:INT)
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "MINUS"))
    {
        if (!strcmp(((Exp->cld)[1]->cld)[0]->name, "INT"))
        {
            int value = -(int)(((Exp->cld)[1]->cld)[0]->value);
            Operand result = find_Const(value);
            if (result == NULL)
                return new_Const(value);
            else
                return result;
        }
    }
    return NULL;
}
// 查看是否已经声明过同一个常数值的临时变量
Operand find_Const(int value)
{
    int i;
    for (i = 0; i < 100; i++)
    {
        if (tempvar[i] == -1)
            break;
        if (temp_Operands[i]->kind == TEMPVAR && temp_Operands[i]->value == value)
            return temp_Operands[i];
    }
    return NULL;
}

   由于采用双向链表的存储方式,可以在递归分析过程中进行中间代码的拼接,add_Code函数采用变长参数,简化了生成过程:

// 获取链表的尾部
InterCode get_Tail(InterCode codes)
{
    InterCode temp = codes;
    while (temp->next)
    {
        temp = temp->next;
    }
    return temp;
}
// 在链表末尾加上另一条链表
InterCode add_Codes(int num, ...)
{
    int i;
    // 参数列表,详见 stdarg.h 用法
    va_list list;
    // 初始化参数列表
    va_start(list, num);
    // 拼接中间代码
    InterCode code = va_arg(list, InterCode);
    InterCode temp = new_Code();
    InterCode tail = new_Code();
    for (i = 1; i < num; i++)
    {
        temp = va_arg(list, InterCode);
        tail = get_Tail(code);
        tail->next = temp;
        temp->prev = tail;
    }
    return code;
}

   在生成代码后,对于不同类型的中间代码和操作数,采用不同的打印方式:

// 打印一条中间代码
void print_Code(InterCode code)
{
    if (code == NULL)
    {
        printf("Error, InterCode is NULL\n");
        return;
    }
    switch (code->kind)
    {
    case _NULL: // 代码为空
        // printf("Code NULL");
        break;
    case _LABLE: // 定义标号
        printf("LABLE ");
        print_Operand(code->operands.var);
        break;
    case _FUNCTION: // 定义函数
        printf("FUNCTION ");
        print_Operand(code->operands.var);
        break;
    case _ASSIGN: // =
        print_Operand(code->operands.assign.left);
        printf(" := ");
        print_Operand(code->operands.assign.right);
        break;
    case _ADD: // +
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" + ");
        print_Operand(code->operands.binop.op2);
        break;
    case _SUB: // -
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" - ");
        print_Operand(code->operands.binop.op2);
        break;
    case _MUL: // *
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" * ");
        print_Operand(code->operands.binop.op2);
        break;
    case _DIV: // /
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" / ");
        print_Operand(code->operands.binop.op2);
        break;
    case _GOTO: // 无条件跳转
        printf("GOTO ");
        print_Operand(code->operands.jump.lable);
        break;
    case _IFGOTO: // 判断跳转
        printf("IF ");
        print_Operand(code->operands.jump.op1);
        printf(" %s ", code->operands.jump.relop);
        print_Operand(code->operands.jump.op2);
        printf(" GOTO ");
        print_Operand(code->operands.jump.lable);
        break;
    case _RETURN: // 函数返回
        printf("RETURN ");
        print_Operand(code->operands.var);
        break;
    case _ARG: // 传实参
        printf("ARG ");
        print_Operand(code->operands.var);
        break;
    case _CALL: // 函数调用
        if (code->operands.assign.left == NULL)
        {
            printf("CALL ");
        }
        else
        {
            print_Operand(code->operands.assign.left);
            printf(" := CALL ");
        }
        print_Operand(code->operands.assign.right);
        break;
    case _PARAM: // 函数参数声明
        printf("PARAM ");
        print_Operand(code->operands.var);
        break;
    case _READ: // 从控制台读取x
        printf("READ ");
        print_Operand(code->operands.var);
        break;
    case _WRITE: // 向控制台打印x
        printf("WRITE ");
        print_Operand(code->operands.var);
        break;
    default:
        printf("Code Error");
        break;
    }
    if (code->kind != _NULL)
        printf("\n");
}

// 打印一个操作数
void print_Operand(Operand op)
{
    if (op == NULL)
    {
        printf("Error, Operand is NULL\n");
        return;
    }
    switch (op->kind)
    {
    case VARIABLE:
    case FUNC:
        printf("%s", op->operand.name);
        break;
    case TEMPVAR:
        printf("t%d", op->operand.tempvar);
        break;
    case LABLE:
        printf("lable%d", op->operand.lable);
        break;
    case CONSTANT:
        printf("#%d", op->operand.value);
        break;
    case ADDRESS:
        printf("&%s", op->operand.name);
        break;
    case VALUE:
        printf("#%s", op->operand.name);
        break;
    default:
        printf("Operand Error");
        break;
    }
}

   由于中间代码是对语法树进行分析,因此需要完成对不同节点类型的生成函数。本次实验我实现了对于大部分类型的语法分析树节点的翻译:

// 整体程序的翻译模式
InterCode translate_Program(tnode Program);
InterCode translate_ExtDefList(tnode ExtDefList);
InterCode translate_ExtDef(tnode ExtDef);

// 变量、函数声明的翻译模式
InterCode translate_FunDec(tnode FunDec);
InterCode translate_VarList(tnode VarList);
InterCode translate_ParamDec(tnode ParamDec);

// 作用域的翻译模式
InterCode translate_CompSt(tnode ComSt);
// 语句列表的翻译模式
InterCode translate_StmtList(tnode);
// 语句的翻译模式
InterCode translate_Stmt(tnode Stmt);

// 变量声明、初始化的翻译模式
InterCode translate_DefList(tnode DefList);
InterCode translate_Def(tnode Def);
InterCode translate_DecList(tnode DecList);
InterCode translate_Dec(tnode Dec);

// 基本表达式的翻译模式
InterCode translate_Exp(tnode Exp, Operand place);
// 条件表达式的翻译模式
InterCode translate_Cond(tnode Exp, Operand lable_true, Operand lable_false);
// 函数参数的翻译模式
InterCode translate_Args(tnode Args, ArgList arg_list);

   下面主要对语句、基本表达式、条件表达式、函数参数的翻译模式进行分析。
   语句的翻译模式如下:
在这里插入图片描述

// 语句的翻译模式
InterCode translate_Stmt(tnode Stmt)
{
    // Exp SEMI
    if (Stmt->ncld == 2 && !strcmp((Stmt->cld)[1]->name, "SEMI"))
    {
        return translate_Exp((Stmt->cld)[0], NULL);
    }
    // Compst
    else if (Stmt->ncld == 1 && !strcmp((Stmt->cld)[0]->name, "Compst"))
    {
        // Preorder((Stmt->cld)[0],0);
        return translate_CompSt((Stmt->cld)[0]);
    }
    // RETURN Exp SEMI
    else if (Stmt->ncld == 3 && !strcmp((Stmt->cld)[0]->name, "RETURN"))
    {
        // 中间代码优化
        Operand existOp = get_Operand((Stmt->cld)[1]);
        if (existOp == NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Stmt->cld)[1], t1);
            InterCode code2 = new_Code();
            code2->kind = _RETURN;
            code2->operands.var = t1;
            return add_Codes(2, code1, code2);
        }
        else
        {
            InterCode code1 = new_Code();
            code1->kind = _RETURN;
            code1->operands.var = existOp;
            return code1;
        }
    }
    // IF LP Exp RP Stmt
    else if (Stmt->ncld == 5 && !strcmp((Stmt->cld)[0]->name, "IF"))
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        InterCode code1 = translate_Cond((Stmt->cld)[2], lable1, lable2);
        InterCode code2 = translate_Stmt((Stmt->cld)[4]);
        return add_Codes(4, code1, new_lable_Code(lable1), code2, new_lable_Code(lable2));
    }
    // IF LP Exp RP Stmt ELSE Stmt
    else if (Stmt->ncld == 7 && !strcmp((Stmt->cld)[0]->name, "IF"))
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        Operand lable3 = new_lable();
        InterCode code1 = translate_Cond((Stmt->cld)[2], lable1, lable2);
        // print_Codes(code1);
        InterCode code2 = translate_Stmt((Stmt->cld)[4]);
        InterCode code3 = translate_Stmt((Stmt->cld)[6]);
        return add_Codes(7, code1, new_lable_Code(lable1), code2, new_goto_Code(lable3), new_lable_Code(lable2), code3, new_lable_Code(lable3));
    }
    // WHILE LP Exp RP Stmt
    else if (Stmt->ncld == 5 && !strcmp((Stmt->cld)[0]->name, "WHILE"))
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        Operand lable3 = new_lable();
        InterCode code1 = translate_Cond((Stmt->cld)[2], lable2, lable3);
        InterCode code2 = translate_Stmt((Stmt->cld)[4]);
        return add_Codes(6, new_lable_Code(lable1), code1, new_lable_Code(lable2), code2, new_goto_Code(lable1), new_lable_Code(lable3));
    }
    return new_Code();
}

   对于基本表达式的翻译模式参考下图实现:
在这里插入图片描述
   在进行基本表达式的翻译时可以实现中间代码的优化,对于变量类型、常数类型的操作数不再申请临时变量对其进行存储,直接输出即可,对于临时变量,查看临时变量表中是否有存有同样值的临时变量,如果有直接使用即可。
   如果Exp产生了一个整数INT,那么我们只需要为传入的 place变量赋值成前面加上一个“#”的相应数值即可。
   如果Exp产生了一个标识符ID,那么我们只需要为传入的 place变量赋值成ID对应的变量名(或该变量对应的中间代码中的名字)即可。
   如果Exp产生了赋值表达式Exp1 ASSIGNOP Exp22,由于之前提到过作为左值的Exp1只能是三种情况之一(单个变量访问、数组元素访问或结构体特定域的访问)我们需要通过查表找到ID对应的变量,然后对Exp2进行翻译,将运算结果储存在临时变量t1中,再将t1中的值赋于ID所对应的变量并将结果再存 place,最后把刚翻译好的这两段代码合并随后返回即可。

// 基本表达式的翻译模式
InterCode translate_Exp(tnode Exp, Operand place)
{
    int isCond = 0;
    // INT
    if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "INT"))
    {
        Operand value = new_Const((Exp->cld)[0]->value);
        InterCode code = new_assign_Code(place, value);
        return code;
    }
    // ID
    else if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "ID"))
    {
        Operand variable = new_Variable((Exp->cld)[0]->content);
        InterCode code = new_assign_Code(place, variable);
        return code;
    }
    // Exp1 ASSIGNOP Exp2
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "ASSIGNOP"))
    {
        // Exp1 -> ID
        if ((Exp->cld)[0]->ncld == 1 && !strcmp(((Exp->cld)[0]->cld)[0]->name, "ID"))
        {
            Operand variable = new_Variable(((Exp->cld)[0]->cld)[0]->content);
            Operand existOp = get_Operand((Exp->cld)[2]);
            // 中间代码优化
            if (existOp == NULL)
            {
                Operand t1 = new_tempvar();
                InterCode code1 = translate_Exp((Exp->cld)[2], t1);
                InterCode code2 = new_assign_Code(variable, t1);
                if (place == NULL)
                    return add_Codes(2, code1, code2);
                else
                {
                    InterCode code3 = new_assign_Code(place, variable);
                    return add_Codes(3, code1, code2, code3);
                }
            }
            else
            {
                return new_assign_Code(variable, existOp);
            }
        }
    }

   四则运算(加减乘处)采用同样的翻译方式,先对Exp1进行翻译,运算结果储存在临时变量t1中,再对Exp2行翻译 (运算结果储存在临时变量t2中,最后生成一句中间代码 place=t1+t2,并将刚翻译好的这三段代码合并后返回即可:

    // Exp PLUS Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "PLUS"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        if (op1 != NULL && op2 != NULL)
        {
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = op2;
            return code3;
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = op2;
            return add_Codes(2, code1, code3);
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = t2;
            return add_Codes(2, code2, code3);
        }
        else
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = t2;
            return add_Codes(3, code1, code2, code3);
        }
    }

   如果Exp产生了取MINUS负表达式 Expl1,则先对Exp进行翻译(运算结果储存在临时变量t1中),再生成一句中间代码 place: =#0-1从而实现对t1取负,最后将翻译好的这两段代码合并后返回:

    // MINUS Exp
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "MINUS"))
    {
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Exp->cld)[1], t1);
        InterCode code2 = new_Code();
        code2->kind = _SUB;
        code2->operands.binop.result = place;
        code2->operands.binop.op1 = new_Const(0);
        code2->operands.binop.op2 = t1;
        return add_Codes(2, code1, code2);
    }

   如果Exp产生了条件表达式(包括与、或、非运算以及比较运算的表达式),我们则会调用 translate_Cond函数进行(短路) 翻译。如果条件表达式为真,那么为 place赋值1;否则,为其赋值0:

    // Exp RELOP Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "RELOP"))
    {
        isCond = 1;
    }
    // NOT Exp
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "NOT"))
    {
        isCond = 1;
    }
    // Exp AND Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "AND"))
    {
        isCond = 1;
    }
    // Exp OR Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "OR"))
    {
        isCond = 1;
    }
    if (isCond)
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        InterCode code0 = new_assign_Code(place, new_Const(0));
        InterCode code1 = translate_Cond(Exp, lable1, lable2);
        InterCode code2 = add_Codes(2, new_lable_Code(lable1), new_assign_Code(place, new_Const(1)));
        return add_Codes(4, code0, code1, code2, new_lable_Code(lable2));
    }

   对于条件表达式的翻译模式如下:
在这里插入图片描述

// 条件表达式的翻译模式
InterCode translate_Cond(tnode Exp, Operand lable_true, Operand lable_false)
{
    // Exp RELOP Exp
    if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "RELOP"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        InterCode code3 = new_Code();
        code3->kind = _IFGOTO;
        code3->operands.jump.lable = lable_true;
        code3->operands.jump.relop = (Exp->cld)[1]->content;
        // 中间代码优化
        if (op1 == NULL && op2 == NULL)
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            code3->operands.jump.op1 = t1;
            code3->operands.jump.op2 = t2;
            return add_Codes(4, code1, code2, code3, new_goto_Code(lable_false));
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            code3->operands.jump.op1 = t1;
            code3->operands.jump.op2 = op2;
            return add_Codes(3, code1, code3, new_goto_Code(lable_false));
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            code3->operands.jump.op1 = op1;
            code3->operands.jump.op2 = t2;
            return add_Codes(3, code2, code3, new_goto_Code(lable_false));
        }
        else if (op1 != NULL && op2 != NULL)
        {
            code3->operands.jump.op1 = op1;
            code3->operands.jump.op2 = op2;
            return add_Codes(2, code3, new_goto_Code(lable_false));
        }
    }
    // NOT Exp
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "NOT"))
    {
        return translate_Cond((Exp->cld)[1], lable_false, lable_true);
    }
    // Exp AND Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "AND"))
    {
        Operand lable1 = new_lable();
        InterCode code1 = translate_Cond((Exp->cld)[0], lable1, lable_false);
        InterCode code2 = translate_Cond((Exp->cld)[2], lable_true, lable_false);
        return add_Codes(3, code1, new_lable_Code(lable1), code2);
    }
    // Exp OR Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "OR"))
    {
        Operand lable1 = new_lable();
        InterCode code1 = translate_Cond((Exp->cld)[0], lable_true, lable1);
        InterCode code2 = translate_Cond((Exp->cld)[2], lable_true, lable_false);
        return add_Codes(3, code1, new_lable_Code(lable1), code2);
    }
    // orther cases
    else
    {
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp(Exp, t1);
        InterCode code2 = new_Code();
        char *relop = "!=";
        code2->kind = _IFGOTO;
        code2->operands.jump.lable = lable_true;
        code2->operands.jump.relop = relop;
        code2->operands.jump.op1 = t1;
        code2->operands.jump.op2 = new_Const(0);
        return add_Codes(3, code1, code2, new_goto_Code(lable_false));
    }
}

   函数调用分为有参调用、无参调用,需要分别进行翻译,对于函数调用的翻译模式如下:
在这里插入图片描述

    // ID LP RP
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "LP"))
    {
        Operand function = new_Operand();
        function->kind = FUNC;
        function->operand.name = (Exp->cld)[0]->content;
        if (!strcmp(function->operand.name, "read"))
        {
            // READ函数处理
            InterCode code = new_Code();
            code->kind = _READ;
            code->operands.var = place;
            return code;
        }
        else
        {
            // 其他函数处理
            InterCode code = new_Code();
            code->kind = _CALL;
            code->operands.assign.left = place;
            code->operands.assign.right = function;
            return code;
        }
    }
    // ID LP Args RP
    else if (Exp->ncld == 4 && !strcmp((Exp->cld)[2]->name, "Args"))
    {
        int i;
        Operand function = new_Operand();
        function->kind = FUNC;
        function->operand.name = (Exp->cld)[0]->content;
        ArgList arg_list = (ArgList)malloc(sizeof(ArgListStru));
        arg_list->num = 0;
        InterCode code1 = translate_Args((Exp->cld)[2], arg_list);
        InterCode code2, code3;
        if (!strcmp(function->operand.name, "write"))
        {
            code2 = new_Code();
            code2->kind = _WRITE;
            code2->operands.var = (arg_list->list)[0];
            return add_Codes(2, code1, code2);
        }
        else
        {
            for (i = 0; i < arg_list->num; i++)
            {
                code2 = new_Code();
                code2->kind = _ARG;
                code2->operands.var = (arg_list->list)[i];
                code1 = add_Codes(2, code1, code2);
            }
            code3 = new_Code();
            code3->kind = _CALL;
            code3->operands.assign.left = place;
            code3->operands.assign.right = function;
            return add_Codes(2, code1, code3);
        }
    }

   进行有参调用时,需要将函数的参数传入,其对应的翻译模式如下:
在这里插入图片描述

// 函数参数的翻译模式
InterCode translate_Args(tnode Args, ArgList arg_list)
{
    // Exp
    if (Args->ncld == 1)
    {
        Operand existOp = get_Operand((Args->cld)[0]);
        if (existOp != NULL)
        {
            if (existOp->kind == CONSTANT)
            {
                Operand t1 = new_tempvar();
                InterCode code1 = new_assign_Code(t1, existOp);
                arg_list->list[arg_list->num] = t1;
                arg_list->num++;
                return code1;
            }
            arg_list->list[arg_list->num] = existOp;
            arg_list->num++;
            return new_Code();
        }
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Args->cld)[0], t1);
        arg_list->list[arg_list->num] = t1;
        arg_list->num++;
        return code1;
    }
    // Exp COMMA Args
    else if (Args->ncld == 3)
    {
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Args->cld)[0], t1);
        arg_list->list[arg_list->num] = t1;
        arg_list->num++;
        InterCode code2 = translate_Args((Args->cld)[2], arg_list);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}

   其他翻译模式技术含量较少,因此不做分析。

3. 目标代码生成

   在完成中间代码的生成以及优化后就可以进行目标代码的生成工作。在linux中没有itoa函数,因此手动编写int类型转char*类型的函数。假设有20个可以进行分配的寄存器(实际上由于进行了代码优化用不了太多寄存器),对于中间代码中的变量、临时变量、常量都需要存储到寄存器中再进行调用:

/**********************目标代码**************************/
// 整数转字符串
char* Int2String(int num,char *str);
// 20个寄存器所存储的内容
Operand regs[20];
int reg_num;
// 分配寄存器
char* allocate_reg(Operand op);
// 根据中间代码生成mips代码
void generate_MIPS_Codes(InterCode codes);
void generate_MIPS_Code(InterCode code);

   分配寄存器的操作,返回的字符串是 t 0 − t0- t0t20以及 z e r o , 对 于 常 数 或 者 临 时 变 量 值 为 0 的 直 接 返 回 zero,对于常数或者临时变量值为0的直接返回 zero0zero,否则查找寄存器中是否已经为该操作数进行了分配,如果已经分配就返回所在寄存器,如果没有就为其分配一个:

// 分配寄存器
char *allocate_reg(Operand op)
{
    int i;
    char *regnumber = (char *)malloc(sizeof(char) * 10);
    char *regname = (char *)malloc(sizeof(char) * 10);
    strcat(regname, "$t");
    // 常数0 寄存器
    if (op->kind == CONSTANT && op->operand.value == 0)
        return "$zero";
    else if (op->kind == TEMPVAR && op->value == 0)
        return "$zero";
    // 寻找存储该操作数的寄存器
    int find = 0;
    for (i = 0; i < reg_num; i++)
    {
        if (regs[i] == NULL || regs[i]->kind != op->kind)
            continue;
        if (regs[i]->kind == CONSTANT && regs[i]->operand.value == op->operand.value)
        {
            find = 1;
            break;
        }
        else if (regs[i]->kind == TEMPVAR && regs[i]->operand.tempvar == op->operand.tempvar)
        {
            find = 1;
            break;
        }
        else if (regs[i]->kind == VARIABLE && !strcmp(regs[i]->operand.name, op->operand.name))
        {
            find = 1;
            break;
        }
    }
    if (find)
    {
        Int2String(i, regnumber);
        strcat(regname, regnumber);
        return regname;
    }
    else
    {
        Int2String(reg_num, regnumber);
        strcat(regname, regnumber);
        regs[reg_num] = op;
        reg_num++;
        return regname;
    }
}

   生成目标代码,本次实验中实现了read、write函数的目标代码生成:

// 根据中间代码生成mips代码
void generate_MIPS_Codes(InterCode codes)
{
    printf("\n目标代码打印:\n");
    // 声明部分
    printf(".data\n_prompt: .asciiz \"Enter an integer:\"\n");
    printf("_ret: .asciiz \"\\n\"\n.globl main\n.text\n");
    // read函数
    printf("read:\n\tli $v0, 4\n\tla $a0, _prompt\n\tsyscall\n");
    printf("\tli $v0, 5\n\tsyscall\n\tjr $ra\n\n");
    // write函数
    printf("write:\n\tli $v0, 1\n\tsyscall\n\tli $v0, 4\n\tla $a0, _ret\n");
    printf("\tsyscall\n\tmove $v0, $0\n\tjr $ra\n\n");
    InterCode temp = new_Code();
    temp = codes;
    while (temp != NULL)
    {
        generate_MIPS_Code(temp);
        temp = temp->next;
    }
    printf("打印完毕\n");
}

   对单条中间代码进行目标代码的生成,生成方法如下:
在这里插入图片描述

// 翻译单条中间代码
void generate_MIPS_Code(InterCode code)
{
    if (code == NULL)
    {
        printf("Error, MIPS is NULL\n");
        return;
    }
    switch (code->kind)
    {
    case _NULL:
        break;
    case _LABLE:
    {
        print_Operand(code->operands.var);
        printf(":\n");
        break;
    }
    case _FUNCTION:
    {
        print_Operand(code->operands.var);
        printf(":\n");
        break;
    }
    case _ASSIGN:
    {
        Operand left = code->operands.assign.left;
        Operand right = code->operands.assign.right;
        if (right->kind == CONSTANT)
        {
            // 如果将0赋给一个临时变量,则不需要输出该mips代码
            if (left->kind == TEMPVAR && right->value == 0)
                break;
            else
                printf("\tli %s, %d\n", allocate_reg(left), right->operand.value);
        }
        else
        {
            printf("\tmove %s, %s\n", allocate_reg(left), allocate_reg(right));
        }
        break;
    }
    case _ADD:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        if (op2->kind == CONSTANT)
        {
            printf("\taddi %s, %s, %d\n", allocate_reg(result), allocate_reg(op1), op2->value);
        }
        else
        {
            printf("\tadd %s, %s, %s\n", allocate_reg(result), allocate_reg(op1), allocate_reg(op2));
        }
        break;
    }
    case _SUB:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        if (op2->kind == CONSTANT)
        {
            printf("\taddi %s, %s, %d\n", allocate_reg(result), allocate_reg(op1), -(op2->value));
        }
        else
        {
            printf("\tsub %s, %s, %s\n", allocate_reg(result), allocate_reg(op1), allocate_reg(op2));
        }
        break;
    }
    case _MUL:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        printf("\tmul %s, %s, %s\n", allocate_reg(result), allocate_reg(op1), allocate_reg(op2));
        break;
    }
    case _DIV:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        printf("\tdiv %s, %s\n", allocate_reg(op1), allocate_reg(op2));
        printf("\tmflo %s\n", allocate_reg(result));
        break;
    }
    case _GOTO:
    {
        Operand lable = code->operands.jump.lable;
        printf("\tj ");
        print_Operand(lable);
        printf("\n");
        break;
    }
    case _CALL:
    {
        break;
    }
    case _READ:
    {
        Operand op = code->operands.var;
        printf("\taddi $sp, $sp, -4\n");
        printf("\tsw $ra, 0($sp)\n");
        printf("\tjal read\n");
        printf("\tlw $ra, 0($sp)\n");
        printf("\taddi $sp, $sp, 4\n");
        printf("\tmove %s, $v0\n", allocate_reg(op));
        break;
    }
    case _WRITE:
    {
        Operand op = code->operands.var;
        printf("\tmove $a0, %s\n", allocate_reg(op));
        printf("\taddi $sp, $sp, -4\n");
        printf("\tsw $ra, 0($sp)\n");
        printf("\tjal write\n");
        printf("\tlw $ra, 0($sp)\n");
        printf("\taddi $sp, $sp, 4\n");
        break;
    }
    case _RETURN:
    {
        Operand res = code->operands.var;
        printf("\tmove $v0, %s\n", allocate_reg(res));
        printf("\tjr $ra\n");
        break;
    }
    case _IFGOTO:
    {
        char *op = code->operands.jump.relop;
        Operand lable = code->operands.jump.lable;
        Operand op1 = code->operands.jump.op1;
        Operand op2 = code->operands.jump.op2;
        if (!strcmp(op, "=="))
        {
            printf("\tbeq %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, "!="))
        {
            printf("\tbne %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, ">"))
        {
            printf("\tbgt %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, "<"))
        {
            printf("\tblt %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, ">="))
        {
            printf("\tbge %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, "<="))
        {
            printf("\tble %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        break;
    }
    default:
        break;
    }
}

  主要代码分析完毕。

三、结果分析

  工程目录结构如下:
在这里插入图片描述
  其中test.c是测试文件

  程序代码编译过程:

	bison -d syntax_tree.y
	flex syntax_tree.l
	gcc syntax_tree.tab.c syntax_tree.c lex.yy.c -lfl -ly -o parser

1. 测试内容一

   主要用于测试read、write函数,测试条件跳转语句,test.c文件内容:

int main()
{
    int n;
    n = read();
    if (n > 10)
        write(1);
    else if (n < 10)
        write(-1);
    else
        write(0);
    return 0;
}

   运行可执行文件:

	./parser test.c

   输出语法分析树:
在这里插入图片描述
   输出中间代码:
在这里插入图片描述
  输出目标代码:
在这里插入图片描述
  将输出的MIPS代码复制到test.s中,并使用QtMips打开,运行结果如下:
在这里插入图片描述
  根据test.c文件中的代码内容分析,当输入值小于10就输出-1,等于10就输出0,大于10就输出1,可知Mips代码成功运行。

2. 测试内容二

  主要用于测试四则运算、while循环语句,test.c内容如下:

int main()
{
    int a,b,c;
    a = 3+4;
    write(a);
    b = 3*4;
    write(b);
    c=3-4;
    write(c);
    while(c<a)
        c=c+1;
    write(c);
    return 0;
}

  根据分析可知,程序会先后输出7、12、-1、7。
  输出中间代码:
在这里插入图片描述
  输出目标代码:
在这里插入图片描述
  在QtMips中运行该目标代码,结果如下:
在这里插入图片描述
  对比可知代码运行正确。

四、源代码放送

syntax_tree.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h> // 变长参数函数 头文件

/**********************语法分析**************************/
// 行数
extern int yylineno;
// 文本
extern char *yytext;
// 错误处理
void yyerror(char *msg);

// 抽象语法树
typedef struct treeNode
{
    // 行数
    int line;
    // Token类型
    char *name;
    // 1变量 2函数 3常数 4数组 5结构体
    int tag;
    // 使用孩子数组表示法
    struct treeNode *cld[10];
    int ncld;
    // 语义值
    char *content;
    // 数据类型 int 或 float
    char *type;
    // 变量的值
    float value;
} * Ast, *tnode;

// 构造抽象语法树(节点)
Ast newAst(char *name, int num, ...);

// 先序遍历语法树
void Preorder(Ast ast, int level);

// 所有节点数量
int nodeNum;
// 存放所有节点
tnode nodeList[5000];
int nodeIsChild[5000];
// 设置节点打印状态
void setChildTag(tnode node);

// bison是否有词法语法错误
int hasFault;

/**********************语义分析**************************/
// 分析语法树,建立符号表
void analysis(tnode val);

// 变量符号表的结点
typedef struct var_
{
    char *name;
    char *type;
    // 是否为结构体域
    int inStruc;
    // 所属的结构体编号
    int strucNum;
    struct var_ *next;
} var;
var *varhead, *vartail;
char* curType;
// 建立变量符号
void newvar(int num, ...);
// 变量是否已经定义
int findvar(tnode val);
// 变量类型
char *typevar(tnode val);
// 这样赋值号左边仅能出现ID、Exp LB Exp RB 以及 Exp DOT ID
int checkleft(tnode val);

// 函数符号表的结点
typedef struct func_
{
    int tag; //0表示未定义,1表示定义
    char *name;
    char *type;
    // 是否为结构体域
    int inStruc;
    // 所属的结构体编号
    int strucNum;
    char *rtype; //声明返回值类型
    int va_num;  //记录函数形参个数
    char *va_type[10];
    struct func_ *next;
} func;
func *funchead, *functail;
// 记录函数实参
int va_num;
char *va_type[10];
void getdetype(tnode val);            //定义的参数
void getretype(tnode val);            //实际的参数
void getargs(tnode Args);             //获取实参
int checkrtype(tnode ID, tnode Args); //检查形参与实参是否一致
// 建立函数符号
void newfunc(int num, ...);
// 函数是否已经定义
int findfunc(tnode val);
// 函数类型
char *typefunc(tnode val);
// 函数的形参个数
int numfunc(tnode val);
// 函数实际返回值类型
char *rtype[10];
int rnum;
void getrtype(tnode val);

// 数组符号表的结点
typedef struct array_
{
    char *name;
    char *type;
    // 是否为结构体域
    int inStruc;
    // 所属的结构体编号
    int strucNum;
    struct array_ *next;
} array;
array *arrayhead, *arraytail;
// 建立数组符号
void newarray(int num, ...);
// 查找数组是否已经定义
int findarray(tnode val);
// 数组类型
char *typearray(tnode val);

// 结构体符号表的结点
typedef struct struc_
{
    char *name;
    char *type;
    // 是否为结构体域
    int inStruc;
    // 所属的结构体编号
    int strucNum;
    struct struc_ *next;
} struc;
struc *struchead, *structail;
// 建立结构体符号
void newstruc(int num, ...);
// 查找结构体是否已经定义
int findstruc(tnode val);
// 当前是结构体域
int inStruc;
// 判断结构体域,{ 和 }是否抵消
int LCnum;
// 当前是第几个结构体
int strucNum;

/**********************中间代码**************************/
// 中间代码数据结构
typedef struct _OperandStru // 操作数
{
    enum
    {
        VARIABLE, // 变量 x
        TEMPVAR,  // 临时变量 t1
        LABLE,    // 标签 lable1
        CONSTANT, // 常数 #1
        ADDRESS,  // 取地址 &x
        VALUE,    // 读取地址的值 *x
        FUNC,     // 函数
    } kind;
    union {
        int tempvar; // 临时变量
        int lable;   // 标签
        int value;   // 常数的值
        char *name;  // 语义值,变量名称、函数名称
    } operand;
    int value;
} OperandStru, *Operand;
typedef struct _InterCodeStru // 中间代码
{
    // 代码类型
    enum
    {
        _LABLE,    // 定义标号
        _FUNCTION, // 定义函数
        _ASSIGN,   // =
        _ADD,      // +
        _SUB,      // -
        _MUL,      // *
        _DIV,      // /
        _GOTO,     // 无条件跳转
        _IFGOTO,   // 判断跳转
        _RETURN,   // 函数返回
        _ARG,      // 传实参
        _CALL,     // 函数调用
        _PARAM,    // 函数参数声明
        _READ,     // 从控制台读取x
        _WRITE,    // 向控制台打印x
        _NULL      // 空的
    } kind;
    // 操作数
    union {
        struct
        { // 赋值 取地址 函数调用等
            Operand left, right;
        } assign;
        struct
        { // 双目运算 + = * /
            Operand result, op1, op2;
        } binop;
        struct
        { // GOTO 和 IF...GOTO
            Operand lable, op1, op2;
            char *relop;
        } jump;
        // 函数声明、参数声明、标签、传实参、函数返回、读取x、打印x
        Operand var;
    } operands;
    struct _InterCodeStru *prev, *next;
} InterCodeStru, *InterCode;
// 函数参数列表
typedef struct _ArgListStru
{
    int num;
    Operand list[10];
} ArgListStru, *ArgList;

InterCode CodesHead, CodesTail; // 全局变量,线性IR双链表的首尾

// 临时变量t1和标签lable1
int tempvar[100];
Operand temp_Operands[100];
int lables[100];
Operand new_tempvar();
Operand new_lable();
void init_tempvar_lable();
// 当Exp的翻译模式为INT、ID、MINUS Exp时,可以获取已经申明过的操作数
Operand get_Operand(tnode Exp);
// 查看是否已经声明过同一个常数值的操作数
Operand find_Const(int value);

// 初始化双链表
void init_InterCode();
// 创建一个新的操作数
Operand new_Operand();
// 创建一个新的变量
Operand new_Variable(char *name);
// 创建一个新的常量
Operand new_Const(float value);
// 创建一条新的中间代码
InterCode new_Code();
// 创建一条lable声明的中间代码
InterCode new_lable_Code(Operand lable);
// 创建一条跳转语句的中间代码
InterCode new_goto_Code(Operand lable);
// 创建一条赋值的中间代码
InterCode new_assign_Code(Operand left, Operand right);
// 打印一条中间代码
void print_Code(InterCode code);
// 打印一个操作数
void print_Operand(Operand op);
// 打印一段中间代码
void print_Codes(InterCode codes);
// 获取链表的尾部
InterCode get_Tail(InterCode codes);
// 在链表末尾加上另一条链表
InterCode add_Codes(int num, ...);

// 整体程序的翻译模式
InterCode translate_Program(tnode Program);
InterCode translate_ExtDefList(tnode ExtDefList);
InterCode translate_ExtDef(tnode ExtDef);

// 变量、函数声明的翻译模式
InterCode translate_FunDec(tnode FunDec);
InterCode translate_VarList(tnode VarList);
InterCode translate_ParamDec(tnode ParamDec);

// 作用域的翻译模式
InterCode translate_CompSt(tnode ComSt);
// 语句列表的翻译模式
InterCode translate_StmtList(tnode);
// 语句的翻译模式
InterCode translate_Stmt(tnode Stmt);

// 变量声明、初始化的翻译模式
InterCode translate_DefList(tnode DefList);
InterCode translate_Def(tnode Def);
InterCode translate_DecList(tnode DecList);
InterCode translate_Dec(tnode Dec);

// 基本表达式的翻译模式
InterCode translate_Exp(tnode Exp, Operand place);
// 条件表达式的翻译模式
InterCode translate_Cond(tnode Exp, Operand lable_true, Operand lable_false);
// 函数参数的翻译模式
InterCode translate_Args(tnode Args, ArgList arg_list);

/**********************目标代码**************************/
// 整数转字符串
char* Int2String(int num,char *str);
// 20个寄存器所存储的内容
Operand regs[20];
int reg_num;
// 分配寄存器
char* allocate_reg(Operand op);
// 根据中间代码生成mips代码
void generate_MIPS_Codes(InterCode codes);
void generate_MIPS_Code(InterCode code);

syntax_tree.c

#include "syntax_tree.h"

// 用于遍历
int i;

Ast newAst(char *name, int num, ...)
{
    // 生成父节点
    tnode father = (tnode)malloc(sizeof(struct treeNode));
    // 添加子节点
    tnode temp = (tnode)malloc(sizeof(struct treeNode));
    if (!father)
    {
        yyerror("create treenode error");
        exit(0);
    }
    father->name = name;
    father->type = NULL;

    // 参数列表,详见 stdarg.h 用法
    va_list list;
    // 初始化参数列表
    va_start(list, num);

    // 表示当前节点不是终结符号,还有子节点
    if (num > 0)
    {
        father->ncld = num;
        // 第一个孩子节点
        temp = va_arg(list, tnode);
        (father->cld)[0] = temp;
        setChildTag(temp);
        // 父节点行号为第一个孩子节点的行号
        father->line = temp->line;
        father->type = temp->type;

        if (num == 1)
        {
            //父节点的语义值等于左孩子的语义值
            father->content = temp->content;
            father->tag = temp->tag;
        }
        else
        {
            for (i = 1; i < num; i++)
            {
                temp = va_arg(list, tnode);
                (father->cld)[i] = temp;
                // 该节点为其他节点的子节点
                setChildTag(temp);
            }
        }
    }
    else //表示当前节点是终结符(叶节点)或者空的语法单元,此时num表示行号(空单元为-1)
    {
        father->ncld = 0;
        father->line = va_arg(list, int);
        // strcmp()==0 表示相同
        if (!strcmp(name, "INT"))
        {
            father->type = "int";
            father->value = atoi(yytext);
        }
        else if (!strcmp(name, "FLOAT"))
        {
            father->type = "float";
            father->value = atof(yytext);
        }
        else
        {
            father->type = curType;
            // 存储词法单元语义值
            char *str;
            str = (char *)malloc(sizeof(char) * 40);
            strcpy(str, yytext);
            father->content = str;
        }
    }
    nodeList[nodeNum] = father;
    nodeNum++;
    // Preorder(father,0);
    return father;
}

// 父节点->左子节点->右子节点....
void Preorder(Ast ast, int level)
{
    if (!strcmp(ast->name, "Program"))
        printf("语法分析树打印:\n");
    int i;
    if (ast != NULL)
    {
        // 空节点不打印
        if (ast->line != -1)
        {
            // 层级结构缩进
            for (i = 0; i < level; ++i)
            {
                printf(" ");
            }
            // 打印节点类型
            printf("%s", ast->name);
            // 根据不同类型打印节点数据
            if ((!strcmp(ast->name, "ID")) || (!strcmp(ast->name, "TYPE")))
            {
                printf(": %s", ast->content);
            }
            else if (!strcmp(ast->name, "INT"))
            {
                printf(": %d", (int)(ast->value));
            }
            else if (!strcmp(ast->name, "FLOAT"))
            {
                printf(": %f", ast->value);
            }
            else
            {
                // 非叶节点打印行号
                printf("(%d)", ast->line);
            }
            printf("\n");
        }
        for (i = 0; i < ast->ncld; i++)
        {
            Preorder((ast->cld)[i], level + 1);
        }
    }
    else
    {
        return;
    }
    if (!strcmp(ast->name, "Program"))
        printf("打印完毕\n");
}

// 错误处理
void yyerror(char *msg)
{
    hasFault = 1;
    fprintf(stderr, "Error type B at Line %d: %s before %s\n", yylineno, msg, yytext);
}

// 设置节点打印状态 该节点为子节点
void setChildTag(tnode node)
{
    int i;
    for (i = 0; i < nodeNum; i++)
    {
        if (nodeList[i] == node)
        {
            nodeIsChild[i] = 1;
        }
    }
}

// 先序遍历分析
void analysis(Ast ast)
{
    int i;
    if (ast != NULL)
    {
        for (i = 0; i < ast->ncld; ++i)
        {
            analysis((ast->cld)[i]);
        }
    }
    else
        return;
}

// 建立变量符号
void newvar(int num, ...)
{
    va_list valist;
    va_start(valist, num);

    var *res = (var *)malloc(sizeof(var));
    tnode temp = (tnode)malloc(sizeof(tnode));

    if (inStruc && LCnum)
    {
        // 是结构体的域
        res->inStruc = 1;
        res->strucNum = strucNum;
    }
    else
    {
        res->inStruc = 0;
        res->strucNum = 0;
    }

    // 变量声明 int i,j
    res->type = curType;
    temp = va_arg(valist, tnode);
    res->name = temp->content;

    vartail->next = res;
    vartail = res;
}
// 查找变量
int findvar(tnode val)
{
    var *temp = (var *)malloc(sizeof(var *));
    temp = varhead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
        {
            if (inStruc && LCnum) // 当前变量是结构体域
            {
                if (!temp->inStruc)
                {
                    // 结构体域与变量重名
                    printf("Error type 9 at Line %d:Struct Field and Variable use the same name.\n", yylineno);
                }
                else if (temp->inStruc && temp->strucNum != strucNum)
                {
                    // 不同结构体中的域重名
                    printf("Error type 10 at Line %d:Struct Fields use the same name.\n", yylineno);
                }
                else
                {
                    // 同一结构体中域名重复
                    return 1;
                }
            }
            else // 当前变量是全局变量
            {
                if (temp->inStruc)
                {
                    // 变量与结构体域重名
                    printf("Error type 9 at Line %d:Struct Field and Variable use the same name.\n", yylineno);
                }
                else
                {
                    // 变量与变量重名,即重复定义
                    return 1;
                }
            }
        }
        temp = temp->next;
    }
    return 0;
}
// 变量类型
char *typevar(tnode val)
{
    var *temp = (var *)malloc(sizeof(var *));
    temp = varhead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
            return temp->type; //返回变量类型
        temp = temp->next;
    }
    return NULL;
}
// 赋值号左边只能出现ID、Exp LB Exp RB 以及 Exp DOT ID
int checkleft(tnode val)
{
    if (val->ncld == 1 && !strcmp((val->cld)[0]->name, "ID"))
        return 1;
    else if (val->ncld == 4 && !strcmp((val->cld)[0]->name, "Exp") && !strcmp((val->cld)[1]->name, "LB") && !strcmp((val->cld)[2]->name, "Exp") && !strcmp((val->cld)[3]->name, "RB"))
        return 1;
    else if (val->ncld == 3 && !strcmp((val->cld)[0]->name, "Exp") && !strcmp((val->cld)[1]->name, "DOT") && !strcmp((val->cld)[2]->name, "ID"))
        return 1;
    else
        return 0;
}

// 创建函数符号
void newfunc(int num, ...)
{
    int i;
    va_list valist;
    va_start(valist, num);

    tnode temp = (tnode)malloc(sizeof(struct treeNode));

    switch (num)
    {
    case 1:
        if (inStruc && LCnum)
        {
            // 是结构体的域
            functail->inStruc = 1;
            functail->strucNum = strucNum;
        }
        else
        {
            functail->inStruc = 0;
            functail->strucNum = 0;
        }
        //设置函数返回值类型
        temp = va_arg(valist, tnode);
        functail->rtype = temp->content;
        functail->type = temp->type;
        for (i = 0; i < rnum; i++)
        {
            if (rtype[i] == NULL || strcmp(rtype[i], functail->rtype))
                printf("Error type 12 at Line %d:Func return type error.\n", yylineno);
        }
        functail->tag = 1; //标志为已定义
        func *new = (func *)malloc(sizeof(func));
        functail->next = new; //尾指针指向下一个空结点
        functail = new;
        break;
    case 2:
        //记录函数名
        temp = va_arg(valist, tnode);
        functail->name = temp->content;
        //设置函数声明时的参数
        temp = va_arg(valist, tnode);
        functail->va_num = 0;
        getdetype(temp);
        break;
    default:
        break;
    }
}
//定义的参数
void getdetype(tnode val)
{
    int i;
    if (val != NULL)
    {
        if (!strcmp(val->name, "ParamDec"))
        {
            functail->va_type[functail->va_num] = (val->cld)[0]->content;
            functail->va_num++;
            return;
        }
        for (i = 0; i < val->ncld; ++i)
        {
            getdetype((val->cld)[i]);
        }
    }
    else
        return;
}
//实际的参数
void getretype(tnode val)
{
    int i;
    if (val != NULL)
    {
        if (!strcmp(val->name, "Exp"))
        {
            va_type[va_num] = val->type;
            va_num++;
            return;
        }
        for (i = 0; i < val->ncld; ++i)
        {
            getretype((val->cld)[i]);
        }
    }
    else
        return;
}
//函数实际返回值类型
void getrtype(tnode val)
{
    rtype[rnum] = val->type;
    rnum++;
}
//检查形参与实参是否一致,没有错误返回0
int checkrtype(tnode ID, tnode Args)
{
    int i;
    va_num = 0;
    getretype(Args);
    func *temp = (func *)malloc(sizeof(func *));
    temp = funchead->next;
    while (temp != NULL && temp->name != NULL && temp->tag == 1)
    {
        if (!strcmp(temp->name, ID->content))
            break;
        temp = temp->next;
    }
    if (va_num != temp->va_num)
        return 1;
    for (i = 0; i < temp->va_num; i++)
    {
        if (temp->va_type[i] == NULL || va_type[i] == NULL || strcmp(temp->va_type[i], va_type[i]) != 0)
            return 1;
    }
    return 0;
}
// 函数是否已经定义
int findfunc(tnode val)
{
    func *temp = (func *)malloc(sizeof(func *));
    temp = funchead->next;
    while (temp != NULL && temp->name != NULL && temp->tag == 1)
    {
        if (!strcmp(temp->name, val->content))
        {
            if (inStruc && LCnum) // 当前变量是结构体域
            {
                if (!temp->inStruc)
                {
                    // 结构体域与变量重名
                    printf("Error type 9 at Line %d:Struct Field and Variable use the same name.\n", yylineno);
                }
                else if (temp->inStruc && temp->strucNum != strucNum)
                {
                    // 不同结构体中的域重名
                    printf("Error type 10 at Line %d:Struct Fields use the same name.\n", yylineno);
                }
                else
                {
                    // 同一结构体中域名重复
                    return 1;
                }
            }
            else // 当前变量是全局变量
            {
                if (temp->inStruc)
                {
                    // 变量与结构体域重名
                    printf("Error type 9 at Line %d:Struct Field and Variable use the same name.\n", yylineno);
                }
                else
                {
                    // 变量与变量重名,即重复定义
                    return 1;
                }
            }
        }
        temp = temp->next;
    }
    return 0;
}
// 函数类型
char *typefunc(tnode val)
{
    func *temp = (func *)malloc(sizeof(func *));
    temp = funchead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
            return temp->rtype; //返回函数类型
        temp = temp->next;
    }
    return NULL;
}
// 形参个数
int numfunc(tnode val)
{
    func *temp = (func *)malloc(sizeof(func *));
    temp = funchead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
            return temp->va_num; //返回形参个数
        temp = temp->next;
    }
}
// 创建数组符号表
void newarray(int num, ...)
{
    va_list valist;
    va_start(valist, num);

    array *res = (array *)malloc(sizeof(array));
    tnode temp = (tnode)malloc(sizeof(struct treeNode));

    if (inStruc && LCnum)
    {
        // 是结构体的域
        res->inStruc = 1;
        res->strucNum = strucNum;
    }
    else
    {
        res->inStruc = 0;
        res->strucNum = 0;
    }
    // int a[10]
    res->type = curType;
    temp = va_arg(valist, tnode);
    res->name = temp->content;
    arraytail->next = res;
    arraytail = res;
}
// 数组是否已经定义
int findarray(tnode val)
{
    array *temp = (array *)malloc(sizeof(array *));
    temp = arrayhead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
            return 1;
        temp = temp->next;
    }
    return 0;
}
// 数组类型
char *typearray(tnode val)
{
    array *temp = (array *)malloc(sizeof(array *));
    temp = arrayhead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
            return temp->type; //返回数组类型
        temp = temp->next;
    }
    return NULL;
}
// 创建结构体符号表
void newstruc(int num, ...)
{
    va_list valist;
    va_start(valist, num);

    struc *res = (struc *)malloc(sizeof(struc));
    tnode temp = (tnode)malloc(sizeof(struct treeNode));

    // struct name{}
    temp = va_arg(valist, tnode);
    res->name = temp->content;
    structail->next = res;
    structail = res;
}
// 结构体是否和结构体或变量的名字重复
int findstruc(tnode val)
{
    struc *temp = (struc *)malloc(sizeof(struc *));
    temp = struchead->next;
    while (temp != NULL)
    {
        if (!strcmp(temp->name, val->content))
            return 1;
        temp = temp->next;
    }
    if (findvar(val) == 1)
        return 1;
    return 0;
}

// 主函数 扫描文件并且分析
// 为bison会自己调用yylex(),所以在main函数中不需要再调用它了
// bison使用yyparse()进行语法分析,所以需要我们在main函数中调用yyparse()和yyrestart()
int main(int argc, char **argv)
{
    int j, tem;
    if (argc < 2)
    {
        return 1;
    }
    for (i = 1; i < argc; i++)
    {
        // 初始化,用于记录结构体域
        inStruc = 0;
        LCnum = 0;
        strucNum = 0;

        // 初始化符号表
        varhead = (var *)malloc(sizeof(var));
        vartail = varhead;
        funchead = (func *)malloc(sizeof(func));
        functail = (func *)malloc(sizeof(func));
        funchead->next = functail;
        functail->va_num = 0;
        arrayhead = (array *)malloc(sizeof(array));
        arraytail = arrayhead;
        struchead = (struc *)malloc(sizeof(struc));
        structail = struchead;
        rnum = 0;

        // 初始化节点记录列表
        nodeNum = 0;
        memset(nodeList, 0, sizeof(tnode) * 5000);
        memset(nodeIsChild, 0, sizeof(int) * 5000);
        hasFault = 0;

        // 初始化临时变量、标签数组
        init_tempvar_lable();

        // 添加read、write函数到符号表
        char *read = "read";
        char *write = "write";
        char *typeInt = "int";
        // read函数
        functail->tag = 1;
        functail->name = read;
        functail->type = typeInt;
        functail->rtype = typeInt;
        functail->va_num = 0;
        functail->inStruc = 0;
        functail->strucNum = 0;
        // 新建节点
        func *new = (func *)malloc(sizeof(func));
        functail->next = new; //尾指针指向下一个空结点
        functail = new;
        // write函数
        functail->tag = 1;
        functail->name = write;
        functail->va_num = 1;
        (functail->va_type)[0] = typeInt;
        functail->inStruc = 0;
        functail->strucNum = 0;
        // 新建节点
        new = (func *)malloc(sizeof(func));
        functail->next = new; //尾指针指向下一个空结点
        functail = new;

        // 设置已经分配的寄存器数量
        reg_num = 0;

        FILE *f = fopen(argv[i], "r");
        if (!f)
        {
            perror(argv[i]);
            return 1;
        }
        yyrestart(f);
        yyparse();
        fclose(f);

        // 遍历所有非子节点的节点
        if (hasFault)
            continue;
        for (j = 0; j < nodeNum; j++)
        {
            if (nodeIsChild[j] != 1)
            {
                Preorder(nodeList[j], 0);
                InterCode codes = translate_Program(nodeList[j]);
                print_Codes(codes);
                generate_MIPS_Codes(codes);
            }
        }
    }
}

// int main()
// {
//     int j, tem;
//     // 初始化,用于记录结构体域
//     inStruc = 0;
//     LCnum = 0;
//     strucNum = 0;

//     // 初始化符号表
//     varhead = (var *)malloc(sizeof(var));
//     vartail = varhead;
//     funchead = (func *)malloc(sizeof(func));
//     functail = (func *)malloc(sizeof(func));
//     funchead->next = functail;
//     functail->va_num = 0;
//     arrayhead = (array *)malloc(sizeof(array));
//     arraytail = arrayhead;
//     struchead = (struc *)malloc(sizeof(struc));
//     structail = struchead;
//     rnum = 0;

//     // 初始化节点记录列表
//     nodeNum = 0;
//     memset(nodeList, 0, sizeof(tnode) * 5000);
//     memset(nodeIsChild, 0, sizeof(int) * 5000);
//     hasFault = 0;

//     // 初始化临时变量、标签数组
//     init_tempvar_lable();

//     // 添加read、write函数到符号表
//     char *read = "read";
//     char *write = "write";
//     char *typeInt = "int";
//     // read函数
//     functail->tag = 1;
//     functail->name = read;
//     functail->type = typeInt;
//     functail->rtype = typeInt;
//     functail->va_num = 0;
//     functail->inStruc = 0;
//     functail->strucNum = 0;
//     // 新建节点
//     func *new = (func *)malloc(sizeof(func));
//     functail->next = new; //尾指针指向下一个空结点
//     functail = new;
//     // write函数
//     functail->tag = 1;
//     functail->name = write;
//     functail->va_num = 1;
//     (functail->va_type)[0] = typeInt;
//     functail->inStruc = 0;
//     functail->strucNum = 0;
//     // 新建节点
//     new = (func *)malloc(sizeof(func));
//     functail->next = new; //尾指针指向下一个空结点
//     functail = new;

//     // 设置已经分配的寄存器数量
//     reg_num = 0;

//     FILE *f = fopen("test.c", "r");
//     if (!f)
//     {
//         perror("error");
//         return 1;
//     }
//     yyrestart(f);
//     yyparse();
//     fclose(f);

//     // 遍历所有非子节点的节点
//     if (hasFault)
//         return 0;
//     for (j = 0; j < nodeNum; j++)
//     {
//         if (nodeIsChild[j] != 1)
//         {
//             Preorder(nodeList[j], 0);
//             InterCode codes = translate_Program(nodeList[j]);
//             print_Codes(codes);
//             generate_MIPS_Codes(codes);
//         }
//     }
// }

/**********************中间代码**************************/
// 临时变量以及标签
void init_tempvar_lable()
{
    int i;
    for (i = 0; i < 100; i++)
    {
        // -1表示该临时变量\标签还未被使用
        tempvar[i] = -1;
        lables[i] = -1;
    }
}
Operand new_tempvar()
{
    int i;
    for (i = 0; i < 100; i++)
    {
        if (tempvar[i] == -1)
        {
            tempvar[i] = 1;
            break;
        }
    }
    if (i >= 100)
        return NULL;
    Operand result = new_Operand();
    result->kind = TEMPVAR;
    result->operand.tempvar = i + 1;
    temp_Operands[i] = result;
    return result;
}
Operand new_lable()
{
    int i;
    for (i = 0; i < 100; i++)
    {
        if (lables[i] == -1)
        {
            lables[i] = 1;
            break;
        }
    }
    if (i >= 100)
        return NULL;
    Operand result = new_Operand();
    result->kind = LABLE;
    result->operand.lable = i + 1;
    return result;
}
// 创建一个新的操作数
Operand new_Operand()
{
    Operand result = (Operand)malloc(sizeof(OperandStru));
    result->value = -10000;
    return result;
}
// 创建一个新的变量
Operand new_Variable(char *name)
{
    Operand result = new_Operand();
    result->kind = VARIABLE;
    result->operand.name = name;
    return result;
}
// 创建一个新的常量
Operand new_Const(float value)
{
    Operand result = new_Operand();
    result->kind = CONSTANT;
    result->operand.value = (int)value;
    result->value = (int)value;
    return result;
}
// 创建一条新的中间代码
InterCode new_Code()
{
    InterCode result = (InterCode)malloc(sizeof(InterCodeStru));
    result->kind = _NULL;
    result->prev = NULL;
    result->next = NULL;
    return result;
}
// 创建一条lable声明的中间代码
InterCode new_lable_Code(Operand lable)
{
    InterCode result = new_Code();
    result->kind = _LABLE;
    result->operands.var = lable;
    return result;
}
// 创建一条跳转语句的中间代码
InterCode new_goto_Code(Operand lable)
{
    InterCode result = new_Code();
    result->kind = _GOTO;
    result->operands.jump.lable = lable;
    return result;
}
// 创建一条赋值的中间代码
InterCode new_assign_Code(Operand left, Operand right)
{
    left->value = right->value;
    InterCode result = new_Code();
    result->kind = _ASSIGN;
    result->operands.assign.left = left;
    result->operands.assign.right = right;
    return result;
}
// 打印一条中间代码
void print_Code(InterCode code)
{
    if (code == NULL)
    {
        printf("Error, InterCode is NULL\n");
        return;
    }
    switch (code->kind)
    {
    case _NULL: // 代码为空
        // printf("Code NULL");
        break;
    case _LABLE: // 定义标号
        printf("LABLE ");
        print_Operand(code->operands.var);
        break;
    case _FUNCTION: // 定义函数
        printf("FUNCTION ");
        print_Operand(code->operands.var);
        break;
    case _ASSIGN: // =
        print_Operand(code->operands.assign.left);
        printf(" := ");
        print_Operand(code->operands.assign.right);
        break;
    case _ADD: // +
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" + ");
        print_Operand(code->operands.binop.op2);
        break;
    case _SUB: // -
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" - ");
        print_Operand(code->operands.binop.op2);
        break;
    case _MUL: // *
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" * ");
        print_Operand(code->operands.binop.op2);
        break;
    case _DIV: // /
        print_Operand(code->operands.binop.result);
        printf(" := ");
        print_Operand(code->operands.binop.op1);
        printf(" / ");
        print_Operand(code->operands.binop.op2);
        break;
    case _GOTO: // 无条件跳转
        printf("GOTO ");
        print_Operand(code->operands.jump.lable);
        break;
    case _IFGOTO: // 判断跳转
        printf("IF ");
        print_Operand(code->operands.jump.op1);
        printf(" %s ", code->operands.jump.relop);
        print_Operand(code->operands.jump.op2);
        printf(" GOTO ");
        print_Operand(code->operands.jump.lable);
        break;
    case _RETURN: // 函数返回
        printf("RETURN ");
        print_Operand(code->operands.var);
        break;
    case _ARG: // 传实参
        printf("ARG ");
        print_Operand(code->operands.var);
        break;
    case _CALL: // 函数调用
        if (code->operands.assign.left == NULL)
        {
            printf("CALL ");
        }
        else
        {
            print_Operand(code->operands.assign.left);
            printf(" := CALL ");
        }
        print_Operand(code->operands.assign.right);
        break;
    case _PARAM: // 函数参数声明
        printf("PARAM ");
        print_Operand(code->operands.var);
        break;
    case _READ: // 从控制台读取x
        printf("READ ");
        print_Operand(code->operands.var);
        break;
    case _WRITE: // 向控制台打印x
        printf("WRITE ");
        print_Operand(code->operands.var);
        break;
    default:
        printf("Code Error");
        break;
    }
    if (code->kind != _NULL)
        printf("\n");
}
// 打印一个操作数
void print_Operand(Operand op)
{
    if (op == NULL)
    {
        printf("Error, Operand is NULL\n");
        return;
    }
    switch (op->kind)
    {
    case VARIABLE:
    case FUNC:
        printf("%s", op->operand.name);
        break;
    case TEMPVAR:
        printf("t%d", op->operand.tempvar);
        break;
    case LABLE:
        printf("lable%d", op->operand.lable);
        break;
    case CONSTANT:
        printf("#%d", op->operand.value);
        break;
    case ADDRESS:
        printf("&%s", op->operand.name);
        break;
    case VALUE:
        printf("#%s", op->operand.name);
        break;
    default:
        printf("Operand Error");
        break;
    }
}
// 打印一段中间代码
void print_Codes(InterCode codes)
{
    printf("\n中间代码打印:\n");
    // InterCode temp = new_Code();
    // temp = codes;
    InterCode temp = codes;
    while (temp)
    {
        print_Code(temp);
        temp = temp->next;
    }
    printf("打印完毕\n");
}
// 获取链表的尾部
InterCode get_Tail(InterCode codes)
{
    InterCode temp = codes;
    while (temp->next)
    {
        temp = temp->next;
    }
    return temp;
}
// 在链表末尾加上另一条链表
InterCode add_Codes(int num, ...)
{
    int i;
    // 参数列表,详见 stdarg.h 用法
    va_list list;
    // 初始化参数列表
    va_start(list, num);
    // 拼接中间代码
    InterCode code = va_arg(list, InterCode);
    InterCode temp = new_Code();
    InterCode tail = new_Code();
    for (i = 1; i < num; i++)
    {
        temp = va_arg(list, InterCode);
        tail = get_Tail(code);
        tail->next = temp;
        temp->prev = tail;
    }
    return code;
}

// 整体程序的翻译模式
InterCode translate_Program(tnode Program)
{
    // ExtDefList
    if (Program->ncld == 1)
    {
        return translate_ExtDefList((Program->cld)[0]);
    }
    return new_Code();
}
InterCode translate_ExtDefList(tnode ExtDefList)
{
    // ExtDef ExtDefList
    if (ExtDefList->ncld == 2)
    {
        InterCode code1 = translate_ExtDef((ExtDefList->cld)[0]);
        InterCode code2 = translate_ExtDefList((ExtDefList->cld)[1]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}
InterCode translate_ExtDef(tnode ExtDef)
{
    // Specifire ExtDecList SEMI
    if (ExtDef->ncld == 3 && !strcmp((ExtDef->cld)[1]->name, "ExtDecList"))
    {
        // 函数外变量声明、结构体定义不进行处理
    }
    // Specifire SEMI
    else if (ExtDef->ncld == 2 && !strcmp((ExtDef->cld)[1]->name, "SEMI"))
    {
        // 函数外变量声明、结构体定义不进行处理
    }
    // Specifire FunDec Compst
    else if (ExtDef->ncld == 3 && !strcmp((ExtDef->cld)[1]->name, "FunDec"))
    {
        InterCode code1 = translate_FunDec((ExtDef->cld)[1]);
        InterCode code2 = translate_CompSt((ExtDef->cld)[2]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}

// 变量、函数声明的翻译模式
InterCode translate_FunDec(tnode FunDec)
{
    // ID LP VarList RP
    if (FunDec->ncld == 4)
    {
        Operand function = new_Variable((FunDec->cld)[0]->content);
        InterCode code1 = new_Code();
        code1->kind = _FUNCTION;
        code1->operands.var = function;
        InterCode code2 = translate_VarList((FunDec->cld)[2]);
        return add_Codes(2, code1, code2);
    }
    // ID LP RP
    else if (FunDec->ncld == 3)
    {
        Operand function = new_Variable((FunDec->cld)[0]->content);
        InterCode code1 = new_Code();
        code1->kind = _FUNCTION;
        code1->operands.var = function;
        return code1;
    }
    return new_Code();
}
InterCode translate_VarList(tnode VarList)
{
    // ParamDec
    if (VarList->ncld == 1)
    {
        return translate_ParamDec((VarList->cld)[0]);
    }
    // ParamDec COMMA VarList
    else if (VarList->ncld == 3)
    {
        InterCode code1 = translate_ParamDec((VarList->cld)[0]);
        InterCode code2 = translate_VarList((VarList->cld)[2]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}
InterCode translate_ParamDec(tnode ParamDec)
{
    // Specifire VarDec
    if (ParamDec->ncld == 2)
    {
        // VarDec:ID
        // 忽略数组的情况
        tnode ID = ((ParamDec->cld)[1]->cld)[0];
        InterCode code1 = new_Code();
        code1->kind = _PARAM;
        code1->operands.var = new_Variable(ID->content);
        return code1;
    }
    return new_Code();
}

// 作用域的翻译模式
InterCode translate_CompSt(tnode ComSt)
{
    // printf("%d\n",ComSt->ncld);
    // LC DefList StmtList RC
    if (ComSt->ncld == 4)
    {
        InterCode code1 = translate_DefList((ComSt->cld)[1]);
        InterCode code2 = translate_StmtList((ComSt->cld)[2]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}
// 语句列表的翻译模式
InterCode translate_StmtList(tnode StmtList)
{
    // Stmt StmtList
    if (StmtList->ncld == 2)
    {
        InterCode code1 = translate_Stmt((StmtList->cld)[0]);
        InterCode code2 = translate_StmtList((StmtList->cld)[1]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}
// 语句的翻译模式
InterCode translate_Stmt(tnode Stmt)
{
    // Exp SEMI
    if (Stmt->ncld == 2 && !strcmp((Stmt->cld)[1]->name, "SEMI"))
    {
        return translate_Exp((Stmt->cld)[0], NULL);
    }
    // Compst
    else if (Stmt->ncld == 1 && !strcmp((Stmt->cld)[0]->name, "Compst"))
    {
        // Preorder((Stmt->cld)[0],0);
        return translate_CompSt((Stmt->cld)[0]);
    }
    // RETURN Exp SEMI
    else if (Stmt->ncld == 3 && !strcmp((Stmt->cld)[0]->name, "RETURN"))
    {
        // 中间代码优化
        Operand existOp = get_Operand((Stmt->cld)[1]);
        if (existOp == NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Stmt->cld)[1], t1);
            InterCode code2 = new_Code();
            code2->kind = _RETURN;
            code2->operands.var = t1;
            return add_Codes(2, code1, code2);
        }
        else
        {
            InterCode code1 = new_Code();
            code1->kind = _RETURN;
            code1->operands.var = existOp;
            return code1;
        }
    }
    // IF LP Exp RP Stmt
    else if (Stmt->ncld == 5 && !strcmp((Stmt->cld)[0]->name, "IF"))
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        InterCode code1 = translate_Cond((Stmt->cld)[2], lable1, lable2);
        InterCode code2 = translate_Stmt((Stmt->cld)[4]);
        return add_Codes(4, code1, new_lable_Code(lable1), code2, new_lable_Code(lable2));
    }
    // IF LP Exp RP Stmt ELSE Stmt
    else if (Stmt->ncld == 7 && !strcmp((Stmt->cld)[0]->name, "IF"))
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        Operand lable3 = new_lable();
        InterCode code1 = translate_Cond((Stmt->cld)[2], lable1, lable2);
        // print_Codes(code1);
        InterCode code2 = translate_Stmt((Stmt->cld)[4]);
        InterCode code3 = translate_Stmt((Stmt->cld)[6]);
        return add_Codes(7, code1, new_lable_Code(lable1), code2, new_goto_Code(lable3), new_lable_Code(lable2), code3, new_lable_Code(lable3));
    }
    // WHILE LP Exp RP Stmt
    else if (Stmt->ncld == 5 && !strcmp((Stmt->cld)[0]->name, "WHILE"))
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        Operand lable3 = new_lable();
        InterCode code1 = translate_Cond((Stmt->cld)[2], lable2, lable3);
        InterCode code2 = translate_Stmt((Stmt->cld)[4]);
        return add_Codes(6, new_lable_Code(lable1), code1, new_lable_Code(lable2), code2, new_goto_Code(lable1), new_lable_Code(lable3));
    }
    return new_Code();
}

// 变量声明、初始化的翻译模式
InterCode translate_DefList(tnode DefList)
{
    // Def DefList
    if (DefList->ncld == 2)
    {
        InterCode code1 = translate_Def((DefList->cld)[0]);
        InterCode code2 = translate_DefList((DefList->cld)[1]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}
InterCode translate_Def(tnode Def)
{
    // Specifire DecList SEMI
    if (Def->ncld == 3)
    {
        return translate_DecList((Def->cld)[1]);
    }
    return new_Code();
}
InterCode translate_DecList(tnode DecList)
{
    // Dec
    if (DecList->ncld == 1)
    {
        return translate_Dec((DecList->cld)[0]);
    }
    // Dec COMMA DecList
    else if (DecList->ncld == 3)
    {
        InterCode code1 = translate_Dec((DecList->cld)[0]);
        InterCode code2 = translate_DecList((DecList->cld)[2]);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}
InterCode translate_Dec(tnode Dec)
{
    // VarDec ASSIGNOP Exp
    if (Dec->ncld == 3)
    {
        // 没有处理数组
        // VarDec:ID
        tnode ID = ((Dec->cld)[0]->cld)[0];
        Operand variable = new_Variable(ID->content);
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Dec->cld)[2], t1);
        InterCode code2 = new_assign_Code(variable, t1);
        return add_Codes(2, code1, code2);
    }
    // VarDec
    return new_Code();
}

// 当Exp的翻译模式为INT、ID、MINUS Exp时,可以获取已经申明过的操作数
Operand get_Operand(tnode Exp)
{
    // INT
    if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "INT"))
    {
        return find_Const((int)((Exp->cld)[0]->value));
    }
    // ID
    else if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "ID"))
    {
        Operand variable = new_Variable((Exp->cld)[0]->content);
        return variable;
    }
    // MINUS Exp  (Exp:INT)
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "MINUS"))
    {
        if (!strcmp(((Exp->cld)[1]->cld)[0]->name, "INT"))
        {
            int value = -(int)(((Exp->cld)[1]->cld)[0]->value);
            Operand result = find_Const(value);
            if (result == NULL)
                return new_Const(value);
            else
                return result;
        }
    }
    return NULL;
}
// 查看是否已经声明过同一个常数值的临时变量
Operand find_Const(int value)
{
    int i;
    for (i = 0; i < 100; i++)
    {
        if (tempvar[i] == -1)
            break;
        if (temp_Operands[i]->kind == TEMPVAR && temp_Operands[i]->value == value)
            return temp_Operands[i];
    }
    return NULL;
}

// 基本表达式的翻译模式
InterCode translate_Exp(tnode Exp, Operand place)
{
    int isCond = 0;
    // INT
    if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "INT"))
    {
        Operand value = new_Const((Exp->cld)[0]->value);
        InterCode code = new_assign_Code(place, value);
        return code;
    }
    // ID
    else if (Exp->ncld == 1 && !strcmp((Exp->cld)[0]->name, "ID"))
    {
        Operand variable = new_Variable((Exp->cld)[0]->content);
        InterCode code = new_assign_Code(place, variable);
        return code;
    }
    // Exp1 ASSIGNOP Exp2
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "ASSIGNOP"))
    {
        // Exp1 -> ID
        if ((Exp->cld)[0]->ncld == 1 && !strcmp(((Exp->cld)[0]->cld)[0]->name, "ID"))
        {
            Operand variable = new_Variable(((Exp->cld)[0]->cld)[0]->content);
            Operand existOp = get_Operand((Exp->cld)[2]);
            // 中间代码优化
            if (existOp == NULL)
            {
                Operand t1 = new_tempvar();
                InterCode code1 = translate_Exp((Exp->cld)[2], t1);
                InterCode code2 = new_assign_Code(variable, t1);
                if (place == NULL)
                    return add_Codes(2, code1, code2);
                else
                {
                    InterCode code3 = new_assign_Code(place, variable);
                    return add_Codes(3, code1, code2, code3);
                }
            }
            else
            {
                return new_assign_Code(variable, existOp);
            }
        }
    }
    // Exp PLUS Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "PLUS"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        if (op1 != NULL && op2 != NULL)
        {
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = op2;
            return code3;
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = op2;
            return add_Codes(2, code1, code3);
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = t2;
            return add_Codes(2, code2, code3);
        }
        else
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _ADD;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = t2;
            return add_Codes(3, code1, code2, code3);
        }
    }
    // Exp MINUS Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "MINUS"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        if (op1 != NULL && op2 != NULL)
        {
            InterCode code3 = new_Code();
            code3->kind = _SUB;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = op2;
            return code3;
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code3 = new_Code();
            code3->kind = _SUB;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = op2;
            return add_Codes(2, code1, code3);
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _SUB;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = t2;
            return add_Codes(2, code2, code3);
        }
        else
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _SUB;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = t2;
            return add_Codes(3, code1, code2, code3);
        }
    }
    // Exp STAR Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "STAR"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        if (op1 != NULL && op2 != NULL)
        {
            InterCode code3 = new_Code();
            code3->kind = _MUL;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = op2;
            return code3;
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code3 = new_Code();
            code3->kind = _MUL;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = op2;
            return add_Codes(2, code1, code3);
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _MUL;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = t2;
            return add_Codes(2, code2, code3);
        }
        else
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _MUL;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = t2;
            return add_Codes(3, code1, code2, code3);
        }
    }
    // Exp DIV Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "DIV"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        if (op1 != NULL && op2 != NULL)
        {
            InterCode code3 = new_Code();
            code3->kind = _DIV;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = op2;
            return code3;
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code3 = new_Code();
            code3->kind = _DIV;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = op2;
            return add_Codes(2, code1, code3);
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _DIV;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = op1;
            code3->operands.binop.op2 = t2;
            return add_Codes(2, code2, code3);
        }
        else
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            InterCode code3 = new_Code();
            code3->kind = _DIV;
            code3->operands.binop.result = place;
            code3->operands.binop.op1 = t1;
            code3->operands.binop.op2 = t2;
            return add_Codes(3, code1, code2, code3);
        }
    }
    // MINUS Exp
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "MINUS"))
    {
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Exp->cld)[1], t1);
        InterCode code2 = new_Code();
        code2->kind = _SUB;
        code2->operands.binop.result = place;
        code2->operands.binop.op1 = new_Const(0);
        code2->operands.binop.op2 = t1;
        return add_Codes(2, code1, code2);
    }
    // Exp RELOP Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "RELOP"))
    {
        isCond = 1;
    }
    // NOT Exp
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "NOT"))
    {
        isCond = 1;
    }
    // Exp AND Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "AND"))
    {
        isCond = 1;
    }
    // Exp OR Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "OR"))
    {
        isCond = 1;
    }
    // ID LP RP
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "LP"))
    {
        Operand function = new_Operand();
        function->kind = FUNC;
        function->operand.name = (Exp->cld)[0]->content;
        if (!strcmp(function->operand.name, "read"))
        {
            // READ函数处理
            InterCode code = new_Code();
            code->kind = _READ;
            code->operands.var = place;
            return code;
        }
        else
        {
            // 其他函数处理
            InterCode code = new_Code();
            code->kind = _CALL;
            code->operands.assign.left = place;
            code->operands.assign.right = function;
            return code;
        }
    }
    // ID LP Args RP
    else if (Exp->ncld == 4 && !strcmp((Exp->cld)[2]->name, "Args"))
    {
        int i;
        Operand function = new_Operand();
        function->kind = FUNC;
        function->operand.name = (Exp->cld)[0]->content;
        ArgList arg_list = (ArgList)malloc(sizeof(ArgListStru));
        arg_list->num = 0;
        InterCode code1 = translate_Args((Exp->cld)[2], arg_list);
        InterCode code2, code3;
        if (!strcmp(function->operand.name, "write"))
        {
            code2 = new_Code();
            code2->kind = _WRITE;
            code2->operands.var = (arg_list->list)[0];
            return add_Codes(2, code1, code2);
        }
        else
        {
            for (i = 0; i < arg_list->num; i++)
            {
                code2 = new_Code();
                code2->kind = _ARG;
                code2->operands.var = (arg_list->list)[i];
                code1 = add_Codes(2, code1, code2);
            }
            code3 = new_Code();
            code3->kind = _CALL;
            code3->operands.assign.left = place;
            code3->operands.assign.right = function;
            return add_Codes(2, code1, code3);
        }
    }
    else
    {
        printf("不能处理该类型的语句\n");
    }
    if (isCond)
    {
        Operand lable1 = new_lable();
        Operand lable2 = new_lable();
        InterCode code0 = new_assign_Code(place, new_Const(0));
        InterCode code1 = translate_Cond(Exp, lable1, lable2);
        InterCode code2 = add_Codes(2, new_lable_Code(lable1), new_assign_Code(place, new_Const(1)));
        return add_Codes(4, code0, code1, code2, new_lable_Code(lable2));
    }
    return new_Code();
}
// 条件表达式的翻译模式
InterCode translate_Cond(tnode Exp, Operand lable_true, Operand lable_false)
{
    // Exp RELOP Exp
    if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "RELOP"))
    {
        Operand op1 = get_Operand((Exp->cld)[0]);
        Operand op2 = get_Operand((Exp->cld)[2]);
        InterCode code3 = new_Code();
        code3->kind = _IFGOTO;
        code3->operands.jump.lable = lable_true;
        code3->operands.jump.relop = (Exp->cld)[1]->content;
        // 中间代码优化
        if (op1 == NULL && op2 == NULL)
        {
            Operand t1 = new_tempvar();
            Operand t2 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            code3->operands.jump.op1 = t1;
            code3->operands.jump.op2 = t2;
            return add_Codes(4, code1, code2, code3, new_goto_Code(lable_false));
        }
        else if (op1 == NULL && op2 != NULL)
        {
            Operand t1 = new_tempvar();
            InterCode code1 = translate_Exp((Exp->cld)[0], t1);
            code3->operands.jump.op1 = t1;
            code3->operands.jump.op2 = op2;
            return add_Codes(3, code1, code3, new_goto_Code(lable_false));
        }
        else if (op1 != NULL && op2 == NULL)
        {
            Operand t2 = new_tempvar();
            InterCode code2 = translate_Exp((Exp->cld)[2], t2);
            code3->operands.jump.op1 = op1;
            code3->operands.jump.op2 = t2;
            return add_Codes(3, code2, code3, new_goto_Code(lable_false));
        }
        else if (op1 != NULL && op2 != NULL)
        {
            code3->operands.jump.op1 = op1;
            code3->operands.jump.op2 = op2;
            return add_Codes(2, code3, new_goto_Code(lable_false));
        }
    }
    // NOT Exp
    else if (Exp->ncld == 2 && !strcmp((Exp->cld)[0]->name, "NOT"))
    {
        return translate_Cond((Exp->cld)[1], lable_false, lable_true);
    }
    // Exp AND Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "AND"))
    {
        Operand lable1 = new_lable();
        InterCode code1 = translate_Cond((Exp->cld)[0], lable1, lable_false);
        InterCode code2 = translate_Cond((Exp->cld)[2], lable_true, lable_false);
        return add_Codes(3, code1, new_lable_Code(lable1), code2);
    }
    // Exp OR Exp
    else if (Exp->ncld == 3 && !strcmp((Exp->cld)[1]->name, "OR"))
    {
        Operand lable1 = new_lable();
        InterCode code1 = translate_Cond((Exp->cld)[0], lable_true, lable1);
        InterCode code2 = translate_Cond((Exp->cld)[2], lable_true, lable_false);
        return add_Codes(3, code1, new_lable_Code(lable1), code2);
    }
    // orther cases
    else
    {
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp(Exp, t1);
        InterCode code2 = new_Code();
        char *relop = "!=";
        code2->kind = _IFGOTO;
        code2->operands.jump.lable = lable_true;
        code2->operands.jump.relop = relop;
        code2->operands.jump.op1 = t1;
        code2->operands.jump.op2 = new_Const(0);
        return add_Codes(3, code1, code2, new_goto_Code(lable_false));
    }
}
// 函数参数的翻译模式
InterCode translate_Args(tnode Args, ArgList arg_list)
{
    // Exp
    if (Args->ncld == 1)
    {
        Operand existOp = get_Operand((Args->cld)[0]);
        if (existOp != NULL)
        {
            if (existOp->kind == CONSTANT)
            {
                Operand t1 = new_tempvar();
                InterCode code1 = new_assign_Code(t1, existOp);
                arg_list->list[arg_list->num] = t1;
                arg_list->num++;
                return code1;
            }
            arg_list->list[arg_list->num] = existOp;
            arg_list->num++;
            return new_Code();
        }
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Args->cld)[0], t1);
        arg_list->list[arg_list->num] = t1;
        arg_list->num++;
        return code1;
    }
    // Exp COMMA Args
    else if (Args->ncld == 3)
    {
        Operand t1 = new_tempvar();
        InterCode code1 = translate_Exp((Args->cld)[0], t1);
        arg_list->list[arg_list->num] = t1;
        arg_list->num++;
        InterCode code2 = translate_Args((Args->cld)[2], arg_list);
        return add_Codes(2, code1, code2);
    }
    return new_Code();
}

/**********************目标代码**************************/
char *Int2String(int num, char *str) //10进制
{
    int i = 0;   //指示填充str
    if (num < 0) //如果num为负数,将num变正
    {
        num = -num;
        str[i++] = '-';
    }
    //转换
    do
    {
        str[i++] = num % 10 + 48; //取num最低位 字符0~9的ASCII码是48~57;简单来说数字0+48=48,ASCII码对应字符'0'
        num /= 10;                //去掉最低位
    } while (num);                //num不为0继续循环

    str[i] = '\0';

    //确定开始调整的位置
    int j = 0;
    if (str[0] == '-') //如果有负号,负号不用调整
    {
        j = 1; //从第二位开始调整
        ++i;   //由于有负号,所以交换的对称轴也要后移1位
    }
    //对称交换
    for (; j < i / 2; j++)
    {
        //对称交换两端的值 其实就是省下中间变量交换a+b的值:a=a+b;b=a-b;a=a-b;
        str[j] = str[j] + str[i - 1 - j];
        str[i - 1 - j] = str[j] - str[i - 1 - j];
        str[j] = str[j] - str[i - 1 - j];
    }

    return str; //返回转换后的值
}

// 分配寄存器
char *allocate_reg(Operand op)
{
    int i;
    char *regnumber = (char *)malloc(sizeof(char) * 10);
    char *regname = (char *)malloc(sizeof(char) * 10);
    strcat(regname, "$t");
    // 常数0 寄存器
    if (op->kind == CONSTANT && op->operand.value == 0)
        return "$zero";
    else if (op->kind == TEMPVAR && op->value == 0)
        return "$zero";
    // 寻找存储该操作数的寄存器
    int find = 0;
    for (i = 0; i < reg_num; i++)
    {
        if (regs[i] == NULL || regs[i]->kind != op->kind)
            continue;
        if (regs[i]->kind == CONSTANT && regs[i]->operand.value == op->operand.value)
        {
            find = 1;
            break;
        }
        else if (regs[i]->kind == TEMPVAR && regs[i]->operand.tempvar == op->operand.tempvar)
        {
            find = 1;
            break;
        }
        else if (regs[i]->kind == VARIABLE && !strcmp(regs[i]->operand.name, op->operand.name))
        {
            find = 1;
            break;
        }
    }
    if (find)
    {
        Int2String(i, regnumber);
        strcat(regname, regnumber);
        return regname;
    }
    else
    {
        Int2String(reg_num, regnumber);
        strcat(regname, regnumber);
        regs[reg_num] = op;
        reg_num++;
        return regname;
    }
}
// 根据中间代码生成mips代码
void generate_MIPS_Codes(InterCode codes)
{
    printf("\n目标代码打印:\n");
    // 声明部分
    printf(".data\n_prompt: .asciiz \"Enter an integer:\"\n");
    printf("_ret: .asciiz \"\\n\"\n.globl main\n.text\n");
    // read函数
    printf("read:\n\tli $v0, 4\n\tla $a0, _prompt\n\tsyscall\n");
    printf("\tli $v0, 5\n\tsyscall\n\tjr $ra\n\n");
    // write函数
    printf("write:\n\tli $v0, 1\n\tsyscall\n\tli $v0, 4\n\tla $a0, _ret\n");
    printf("\tsyscall\n\tmove $v0, $0\n\tjr $ra\n\n");
    InterCode temp = new_Code();
    temp = codes;
    while (temp != NULL)
    {
        generate_MIPS_Code(temp);
        temp = temp->next;
    }
    printf("打印完毕\n");
}
// 翻译单条中间代码
void generate_MIPS_Code(InterCode code)
{
    if (code == NULL)
    {
        printf("Error, MIPS is NULL\n");
        return;
    }
    switch (code->kind)
    {
    case _NULL:
        break;
    case _LABLE:
    {
        print_Operand(code->operands.var);
        printf(":\n");
        break;
    }
    case _FUNCTION:
    {
        print_Operand(code->operands.var);
        printf(":\n");
        break;
    }
    case _ASSIGN:
    {
        Operand left = code->operands.assign.left;
        Operand right = code->operands.assign.right;
        if (right->kind == CONSTANT)
        {
            // 如果将0赋给一个临时变量,则不需要输出该mips代码
            if (left->kind == TEMPVAR && right->value == 0)
                break;
            else
                printf("\tli %s, %d\n", allocate_reg(left), right->operand.value);
        }
        else
        {
            printf("\tmove %s, %s\n", allocate_reg(left), allocate_reg(right));
        }
        break;
    }
    case _ADD:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        if (op2->kind == CONSTANT)
        {
            printf("\taddi %s, %s, %d\n", allocate_reg(result), allocate_reg(op1), op2->value);
        }
        else
        {
            printf("\tadd %s, %s, %s\n", allocate_reg(result), allocate_reg(op1), allocate_reg(op2));
        }
        break;
    }
    case _SUB:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        if (op2->kind == CONSTANT)
        {
            printf("\taddi %s, %s, %d\n", allocate_reg(result), allocate_reg(op1), -(op2->value));
        }
        else
        {
            printf("\tsub %s, %s, %s\n", allocate_reg(result), allocate_reg(op1), allocate_reg(op2));
        }
        break;
    }
    case _MUL:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        printf("\tmul %s, %s, %s\n", allocate_reg(result), allocate_reg(op1), allocate_reg(op2));
        break;
    }
    case _DIV:
    {
        Operand result = code->operands.binop.result;
        Operand op1 = code->operands.binop.op1;
        Operand op2 = code->operands.binop.op2;
        printf("\tdiv %s, %s\n", allocate_reg(op1), allocate_reg(op2));
        printf("\tmflo %s\n", allocate_reg(result));
        break;
    }
    case _GOTO:
    {
        Operand lable = code->operands.jump.lable;
        printf("\tj ");
        print_Operand(lable);
        printf("\n");
        break;
    }
    case _CALL:
    {
        break;
    }
    case _READ:
    {
        Operand op = code->operands.var;
        printf("\taddi $sp, $sp, -4\n");
        printf("\tsw $ra, 0($sp)\n");
        printf("\tjal read\n");
        printf("\tlw $ra, 0($sp)\n");
        printf("\taddi $sp, $sp, 4\n");
        printf("\tmove %s, $v0\n", allocate_reg(op));
        break;
    }
    case _WRITE:
    {
        Operand op = code->operands.var;
        printf("\tmove $a0, %s\n", allocate_reg(op));
        printf("\taddi $sp, $sp, -4\n");
        printf("\tsw $ra, 0($sp)\n");
        printf("\tjal write\n");
        printf("\tlw $ra, 0($sp)\n");
        printf("\taddi $sp, $sp, 4\n");
        break;
    }
    case _RETURN:
    {
        Operand res = code->operands.var;
        printf("\tmove $v0, %s\n", allocate_reg(res));
        printf("\tjr $ra\n");
        break;
    }
    case _IFGOTO:
    {
        char *op = code->operands.jump.relop;
        Operand lable = code->operands.jump.lable;
        Operand op1 = code->operands.jump.op1;
        Operand op2 = code->operands.jump.op2;
        if (!strcmp(op, "=="))
        {
            printf("\tbeq %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, "!="))
        {
            printf("\tbne %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, ">"))
        {
            printf("\tbgt %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, "<"))
        {
            printf("\tblt %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, ">="))
        {
            printf("\tbge %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        else if (!strcmp(op, "<="))
        {
            printf("\tble %s, %s, ", allocate_reg(op1), allocate_reg(op2));
            print_Operand(lable);
            printf("\n");
        }
        break;
    }
    default:
        break;
    }
}

syntax_tree.l

/*
	按照C-Tokens文件中要求定义
    对终结符建立叶子结点,返回Token
	19-10-26
*/


/*第一部分 头文件和变量*/
%{
	#include <stdlib.h>
	#include <stdio.h>
    #include "syntax_tree.h"
    #include "syntax_tree.tab.h"
%}

/*flex属性,记录符号所在行号*/
%option yylineno

/*第二部分 定义正则表达式*/
/*十进制*/
INT_DEC [-+]?0|[1-9][0-9]*
/*十六进制*/
INT_HEX 0[xX][a-fA-F0-9]+
/*八进制*/
INT_OCT 0[1-7][0-7]*
/*二进制*/
INT_BIN 0[bB][01]+
/*INT类型汇总*/
INT {INT_HEX}|{INT_DEC}|{INT_OCT}|{INT_BIN}|{INT_HEX_ERROR}|{INT_OCT_ERROR}|{INT_BIN_ERROR}
/*浮点数-科学计数法*/
FLOAT [-+]?((([0-9]+\.[0-9]*)|([0-9]*\.[0-9]+)|INT)[Ee][-+]?[0-9]+)|({INT}\.[0-9])
/*词法分析输出错误,但是语法分析当做INT进行处理*/
/*十六进制错误*/
INT_HEX_ERROR 0[xX][a-fA-F0-9]*[g-zG-Z]+[a-fA-F0-9]*
/*八进制错误*/
INT_OCT_ERROR 0[0-7]*[89]+[0-7]*
/*二进制错误*/
INT_BIN_ERROR 0[bB][01]*[2-9]+[01]*

/*标识符*/
ID [a-z_A-Z][a-z_A-Z0-9]*

/*关键字*/
STRUCT struct
RETURN return
IF if
ELSE else
WHILE while
TYPE int|float

/*符号*/
SEMI  ;
COMMA ,
ASSIGNOP  =
PLUS  \+
MINUS \-
STAR  \*
DIV   \/
AND   &&
OR    \|\|
DOT   \.
NOT   \!
LP    \(
RP    \)
LB    \[
RB    \]
LC    \{
RC    \}
RELOP >|<|>=|<=|==|!=

/*注释*/
COMMENT ("//".*)|("/*"([*]*(([^*/])+([/])*)*)*"*/")
/*空白符*/
SPACE [ \f\r\t\v]+
/*换行*/
EOL \n
/*未定义字符*/
AERROR .

/*第三部分 操作 action 这里面的注释必须顶格一个空格*/
%%
 /*跳过空白和注释*/
{SPACE} {}
{COMMENT} {}
{EOL} {}
 /*关键字*/
{TYPE} {yylval.type_tnode=newAst("TYPE",0,yylineno);
	char *str;
    str = (char *)malloc(sizeof(char) * 40);
    strcpy(str, yytext);
    curType = str;
	return TYPE;}
{STRUCT} {
	yylval.type_tnode=newAst("STRUCT",0,yylineno); 
	// 结构体数加一
	strucNum++; 
	// 开始扫描结构体定义内容
	inStruc=1; 
	return STRUCT;}
{RETURN} {yylval.type_tnode=newAst("RETURN",0,yylineno); return RETURN;}
{IF} {yylval.type_tnode=newAst("IF",0,yylineno);return IF;}
{ELSE} {yylval.type_tnode=newAst("ELSE",0,yylineno); return ELSE;}
{WHILE} {yylval.type_tnode=newAst("WHILE",0,yylineno); return WHILE;}
 /*数字类型错误*/
{INT_HEX_ERROR} {printf("INT_HEX_ERROR at line %d: charachters \"%s\"\n",yylineno,yytext);}
{INT_OCT_ERROR} {printf("INT_OCT_ERROR at line %d: charachters \"%s\"\n",yylineno,yytext);}
{INT_BIN_ERROR} {printf("INT_BIN_ERROR at line %d: charachters \"%s\"\n",yylineno,yytext);}
 /*数字类型表示*/
{INT} {yylval.type_tnode=newAst("INT",0,yylineno); return INT;}
{FLOAT} {yylval.type_tnode=newAst("FLOAT",0,yylineno); return FLOAT;}
 /*符号*/
{SEMI} {yylval.type_tnode=newAst("SEMI",0,yylineno); return SEMI;}
{COMMA} {yylval.type_tnode=newAst("COMMA",0,yylineno); return COMMA;}
{ASSIGNOP} {yylval.type_tnode=newAst("ASSIGNOP",0,yylineno); return ASSIGNOP;}
{PLUS} {yylval.type_tnode=newAst("PLUS",0,yylineno); return PLUS;}
{MINUS} {yylval.type_tnode=newAst("MINUS",0,yylineno); return MINUS;}
{STAR} {yylval.type_tnode=newAst("STAR",0,yylineno); return STAR;}
{DIV} {yylval.type_tnode=newAst("DIV",0,yylineno); return DIV;}
{AND} {yylval.type_tnode=newAst("AND",0,yylineno); return AND;}
{OR} {yylval.type_tnode=newAst("OR",0,yylineno); return OR;}
{DOT} {yylval.type_tnode=newAst("DOT",0,yylineno); return DOT;}
{NOT} {yylval.type_tnode=newAst("NOT",0,yylineno); return NOT;}
{LP} {yylval.type_tnode=newAst("LP",0,yylineno); return LP;}
{RP} {yylval.type_tnode=newAst("RP",0,yylineno); return RP;}
{LB} {yylval.type_tnode=newAst("LB",0,yylineno); return LB;}
{RB} {yylval.type_tnode=newAst("RB",0,yylineno); return RB;}
{LC} {
	yylval.type_tnode=newAst("LC",0,yylineno); 
	if(inStruc){
		// 结构体定义内部存在LC左花括号
		LCnum++;
	}
	return LC;}
{RC} {
	yylval.type_tnode=newAst("RC",0,yylineno); 
	if(inStruc){
		// 结构体定义内部存在RC右花括号
		LCnum--;
	}
	return RC;}
{RELOP} {yylval.type_tnode=newAst("RELOP",0,yylineno); return RELOP;}
 /*标识符*/
{ID} {yylval.type_tnode=newAst("ID",0,yylineno); return ID;}
 /*错误*/
{AERROR} {
	hasFault=1;
	printf("Error type A at line %d: Mystirious charachter '%s'\n",yylineno,yytext);
}
%%

/*第四部分 函数 function*/
int yywrap()
{
	/*此函数必须由用户提供,或者声明 %option noyywrap
	当词法分析程序遇到文件结尾时,它调用例程yywrap()来找出下一步要做什么
	如果返回0,扫描程序继续扫描,如果返回1,扫描程序就返回报告文件结尾*/
    return 1;
}

syntax_tree.y

/*
*bison语法分析,对每条规则 按照孩子兄弟表示法建立语法结点
*/
%{
#include<unistd.h>
#include<stdio.h>   
#include "syntax_tree.h"
%}

%union{
    tnode type_tnode;
	// 这里声明double是为了防止出现指针错误(segmentation fault)
	double d;
}

/*声明记号*/
%token <type_tnode> INT FLOAT
%token <type_tnode> TYPE STRUCT RETURN IF ELSE WHILE ID COMMENT SPACE SEMI COMMA ASSIGNOP PLUS
%token <type_tnode> MINUS STAR DIV AND OR DOT NOT LP RP LB RB LC RC AERROR RELOP EOL

%type  <type_tnode> Program ExtDefList ExtDef ExtDecList Specifire StructSpecifire 
%type  <type_tnode> OptTag Tag VarDec FunDec VarList ParamDec Compst StmtList Stmt DefList Def DecList Dec Exp Args

/*优先级*/
/*C-minus中定义的运算符的优先级,并没有包括所有C语言的*/
%nonassoc LOWER_THAN_ELSE 
%nonassoc ELSE
%left COMMA
%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left PLUS MINUS
%left STAR DIV
%right NOT 
%left LP RP LB RB DOT


/*产生式*/
/*$$表示左表达式 ${num}表示右边的第几个表达式*/
%%
/*High-level Definitions*/
Program:ExtDefList {$$=newAst("Program",1,$1); }
    ;
ExtDefList:ExtDef ExtDefList {$$=newAst("ExtDefList",2,$1,$2); }
	| {$$=newAst("ExtDefList",0,-1); }
	;
ExtDef:Specifire ExtDecList SEMI    {$$=newAst("ExtDef",3,$1,$2,$3);}    
	|Specifire SEMI	{$$=newAst("ExtDef",2,$1,$2); }
	|Specifire FunDec Compst	{
			$$=newAst("ExtDef",3,$1,$2,$3); 
			// 设置函数声明的返回值类型并检查返回类型错误
			newfunc(1,$1);
		}
	;
ExtDecList:VarDec {
		$$=newAst("ExtDecList",1,$1); 
		// 错误类型7:变量出现重复定义
		if(findvar($1)) 
			printf("Error type 7 at Line %d:Redefined Variable '%s'\n",yylineno,$1->content);
        else newvar(1,$1);
	}
	|VarDec COMMA ExtDecList {$$=newAst("ExtDecList",3,$1,$2,$3); }
	;
/*Specifire*/
Specifire:TYPE {$$=newAst("Specifire",1,$1);}
	|StructSpecifire {$$=newAst("Specifire",1,$1); }
	;
StructSpecifire:STRUCT OptTag LC DefList RC {
		// 结构体定义完成,当前在结构体定义外部
		inStruc = 0;
		$$=newAst("StructSpecifire",5,$1,$2,$3,$4,$5); 
		// 错误类型11:结构体的名字与前面定义过的结构体或变量的名字重复
		if(findstruc($2))	
			printf("Error type 11 at Line %d:Duplicated name '%s'\n",yylineno,$2->content);
        else newstruc(1,$2);
	}
	|STRUCT Tag {$$=newAst("StructSpecifire",2,$1,$2); }
	;
OptTag:ID {$$=newAst("OptTag",1,$1); }
	|{$$=newAst("OptTag",0,-1); }
	;
Tag:ID {$$=newAst("Tag",1,$1); }
	;
/*Declarators*/
VarDec:ID {$$=newAst("VarDec",1,$1); $$->tag=1;$$->content=$1->content;}
	|VarDec LB INT RB {$$=newAst("VarDec",4,$1,$2,$3,$4); $$->content=$1->content;$$->tag=4;}
	;
FunDec:ID LP VarList RP {
		$$=newAst("FunDec",4,$1,$2,$3,$4); $$->content=$1->content;
		// 错误类型8:函数出现重复定义(即同样的函数名出现了不止一次定义)
		if(findfunc($1)) 
			printf("Error type 8 at Line %d:Redefined Function '%s'\n",yylineno,$1->content);
		// 设置函数名称以及参数列表
        else newfunc(2,$1,$3);
	}
	|ID LP RP {
		$$=newAst("FunDec",3,$1,$2,$3); $$->content=$1->content;
		// 错误类型8:函数出现重复定义(即同样的函数名出现了不止一次定义)
		if(findfunc($1)) 
			printf("Error type 8 at Line %d:Redefined Function '%s'\n",yylineno,$1->content);
		// 设置函数名称以及参数列表
        else newfunc(2,$1,$3);
	}
	;
VarList:ParamDec COMMA VarList {$$=newAst("VarList",3,$1,$2,$3); }
	|ParamDec {$$=newAst("VarList",1,$1); }
	;
ParamDec:Specifire VarDec {
		$$=newAst("ParamDec",2,$1,$2); 
		// 错误类型7:变量出现重复定义
		if(findvar($2)||findarray($2))  
			printf("Error type 7 at Line %d:Redefined Variable '%s'\n",yylineno,$2->content);
        else if($2->tag==4) 
			newarray(1,$2);
        else 
			newvar(1,$2);
	}
    ;

/*Statement*/
Compst:LC DefList StmtList RC {$$=newAst("Compst",4,$1,$2,$3,$4); }
	;
StmtList:Stmt StmtList{$$=newAst("StmtList",2,$1,$2); }
	| {$$=newAst("StmtList",0,-1); }
	;
Stmt:Exp SEMI { $$=newAst("Stmt",2,$1,$2); }
	|Compst { $$=newAst("Stmt",1,$1); }
	|RETURN Exp SEMI {
		$$=newAst("Stmt",3,$1,$2,$3);
		    getrtype($2);
	}
    |IF LP Exp RP Stmt %prec LOWER_THAN_ELSE {$$=newAst("Stmt",5,$1,$2,$3,$4,$5); }
    |IF LP Exp RP Stmt ELSE Stmt %prec ELSE {$$=newAst("Stmt",7,$1,$2,$3,$4,$5,$6,$7); }
	|WHILE LP Exp RP Stmt {$$=newAst("Stmt",5,$1,$2,$3,$4,$5); }
	;
/*Local Definitions*/
DefList:Def DefList{$$=newAst("DefList",2,$1,$2); }
	| {$$=newAst("DefList",0,-1); }
	;
Def:Specifire DecList SEMI {
		$$=newAst("Def",3,$1,$2,$3); 
	}
	;
DecList:Dec {$$=newAst("DecList",1,$1); }
	|Dec COMMA DecList {$$=newAst("DecList",3,$1,$2,$3); $$->tag=$3->tag;}
	;
Dec:VarDec {
		$$=newAst("Dec",1,$1); 
		// 错误类型7:变量出现重复定义
		if(findvar($1)||findarray($1))  
			printf("Error type 7 at Line %d:Redefined Variable '%s'\n",yylineno,$1->content);
        else if($1->tag==4) 
			newarray(1,$1);
        else 
			newvar(1,$1);
	}
	|VarDec ASSIGNOP Exp {
		$$=newAst("Dec",3,$1,$2,$3); 
		$$->content=$1->content;
		if(findvar($1)||findarray($1))  
			printf("Error type 7 at Line %d:Redefined Variable '%s'\n",yylineno,$1->content);
        else if($1->tag==4) 
			newarray(1,$1);
        else 
			newvar(1,$1);
	}
	;
/*Expressions*/
Exp:Exp ASSIGNOP Exp{
		$$=newAst("Exp",3,$1,$2,$3); 
		// 当有一边变量是未定义时,不进行处理
		if($1->type==NULL || $3->type==NULL){
			// 不进行任何操作
			// 这里不能用return,否则就会推出bison分析过程
		}else{
			// 错误类型2:赋值号两边的表达式类型不匹配
			if(strcmp($1->type,$3->type))
				printf("Error type 2 at Line %d:Type mismatched for assignment.%s,%s\n",yylineno,$1->type,$3->type);
			// 错误类型3:赋值号左边出现一个只有右值的表达式
			if(!checkleft($1))
				printf("Error type 3 at Line %d:The left-hand side of an assignment must be a variable.\n",yylineno);
		}
		
	}
	|Exp AND Exp{$$=newAst("Exp",3,$1,$2,$3); }
	|Exp OR Exp{$$=newAst("Exp",3,$1,$2,$3); }
	|Exp RELOP Exp{$$=newAst("Exp",3,$1,$2,$3); }
	|Exp PLUS Exp{
		$$=newAst("Exp",3,$1,$2,$3);
		// 错误类型6:操作数类型不匹配或操作数类型与操作符不匹配
		if(strcmp($1->type,$3->type)){
			printf("Error type 6 at Line %d:Type mismatched for operands.\n",yylineno);
		}
	}
	|Exp MINUS Exp{
		$$=newAst("Exp",3,$1,$2,$3); 
		// 错误类型6:操作数类型不匹配或操作数类型与操作符不匹配
		if(strcmp($1->type,$3->type))
			printf("Error type 6 at Line %d:Type mismatched for operands.\n",yylineno);
	}
	|Exp STAR Exp{
		$$=newAst("Exp",3,$1,$2,$3); 
		// 错误类型6:操作数类型不匹配或操作数类型与操作符不匹配
		if(strcmp($1->type,$3->type))
			printf("Error type 6 at Line %d:Type mismatched for operands.\n",yylineno);
	}
	|Exp DIV Exp{
		$$=newAst("Exp",3,$1,$2,$3); 
		// 错误类型6:操作数类型不匹配或操作数类型与操作符不匹配
		if(strcmp($1->type,$3->type))
			printf("Error type 6 at Line %d:Type mismatched for operands.\n",yylineno);
	}
	|LP Exp RP{$$=newAst("Exp",3,$1,$2,$3); }
	|MINUS Exp {$$=newAst("Exp",2,$1,$2); }
	|NOT Exp {$$=newAst("Exp",2,$1,$2); }
	|ID LP Args RP {
		$$=newAst("Exp",4,$1,$2,$3,$4); 
		// 错误类型4:对普通变量使用“(...)”或“()”(函数调用)操作符
		if(!findfunc($1) && (findvar($1)||findarray($1)))
			printf("Error type 4 at Line %d:'%s' is not a function.\n",yylineno,$1->content);
		// 错误类型5:函数在调用时未经定义
		else if(!findfunc($1))
			printf("Error type 5 at Line %d:Undefined function %s\n",yylineno,$1->content);
		// 函数实参和形参类型不一致
		else if(checkrtype($1,$3)){
			printf("Error type 13 at Line %d:Function parameter type error.\n",yylineno);
		}else{
			$$->type=typefunc($1);
		}
	}
	|ID LP RP {
		$$=newAst("Exp",3,$1,$2,$3); 
		// 错误类型4:对普通变量使用“(...)”或“()”(函数调用)操作符
		if(!findfunc($1) && (findvar($1)||findarray($1)))
			printf("Error type 4 at Line %d:'%s' is not a function.\n",yylineno,$1->content);
		// 错误类型5:函数在调用时未经定义
		else if(!findfunc($1))
			printf("Error type 5 at Line %d:Undefined function %s\n",yylineno,$1->content);
		else {
			$$->type=typefunc($1);
		}
	}
	|Exp LB Exp RB {$$=newAst("Exp",4,$1,$2,$3,$4); }
	|Exp DOT ID {$$=newAst("Exp",3,$1,$2,$3); }
	|ID {
		$$=newAst("Exp",1,$1); 
		// 错误类型1:变量在使用时未经定义
		if(!findvar($1)&&!findarray($1))
			printf("Error type 1 at Line %d:undefined variable %s\n",yylineno,$1->content);
		else 
			$$->type=typevar($1);
	}
	|INT {$$=newAst("Exp",1,$1); $$->tag=3;$$->value=$1->value;}
	|FLOAT{$$=newAst("Exp",1,$1); $$->tag=3;$$->value=$1->value;}
	;
Args:Exp COMMA Args {$$=newAst("Args",3,$1,$2,$3);}
    |Exp {$$=newAst("Args",1,$1);}
    ;
%%
  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
编译原理是计算机科学中的一门重要课程,涉及了很多与编译器设计和实现相关的概念和技术。而C-minus语法分析则是编译原理中的一个重要部分,它使用了flexbison这两个工具来实现。接下来我将详细介绍C-minus语法分析的相关内容。 C-minus是一种简化版的C语言,它具有类似于C语言的语法和语义。语法分析是编译器的第二个阶段,主要负责通过解析输入的源代码来构建抽象语法树。在C-minus语法分析中,我们使用flexbison这两个工具来实现词法分析和语法分析。 flex是一个用于生成词法分析器的工具,它通过定义一系列正则表达式规则来识别源代码中的各种词法单元,如关键字、标识符、常量等。在C-minus语法分析中,我们可以使用flex来识别源代码中的词法单元,并将它们传递给bison进行后续的语法分析。 bison是一个用于生成语法分析器的工具,它通过定义一系列文法规则来分析词法单元之间的语法关系,同时生成一个由这些规则构成的抽象语法树。在C-minus语法分析中,我们可以使用bison来定义C-minus语言的文法规则,并将其与词法单元进行匹配,从而生成抽象语法树。 在C-minus语法分析中,我们需要定义C-minus语言的文法规则,如声明语句、函数定义、循环语句等。通过使用flexbison这两个工具,我们可以将这些规则转化为相应的词法和语法规则,并实现一个完整的C-minus语法分析器。 总而言之,C-minus语法分析是编译原理中的一个重要环节,通过使用flexbison这两个工具,我们可以实现一个功能完善的C-minus语法分析器,从而为后续的语义分析和代码生成打下基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值