动手实现编译器(十五)——数组(一)

在上一节中,我们实现了注释和变量初始化的功能;在这一节中,我们来实现数组。
先来看看,我们要实现的具体功能:

  int ary[5];               // 定义数组
  ary[3]= 63;               // 表达式给数组元素赋值
  int a;
  a = ary[4];				// 数组元素赋值变量

具体地讲,我们将实现:

  • 具有固定大小但没有初始化列表的数组声明
  • 数组索引作为赋值中的右值
  • 数组索引作为赋值中的左值

数组的SysY语法是

数组定义 VarDef → Ident ‘[’ ConstExp ‘]’

同时,我们暂时只实现一维数组。

修改词法分析

我们的符号表中有标量变量(只有一个值)和函数,现在添加数组类型。同时,要在符号表中增加长度属性,表示数组的长度。

// 结构类型
enum
{
   
   
    S_VARIABLE, S_FUNCTION, S_ARRAY
};

// 符号表结构体
struct symbol_table
{
   
   
    char *name;			        // 符号名
    int type;                   // 类型void或int
    int stype;			        // 结构类型
    int endlabel;			    // 函数的结束标签
    int size;                   // 数组大小
};

同时,往add_global()函数中添加size属性。

// 将全局变量添加到符号表,并返回符号表中的位置
int add_global(char *name, int type, int stype, int endlabel, int size)
{
   
   
	/*......其余代码......*/
    Tsym[y].endlabel = endlabel;
    Tsym[y].size = size;
    return y;
}

接下来,我们开始识别‘[’和’]’,先增加两种单词类型T_LBRACKET, T_RBRACKET,然后在scan()函数中,加入对它们的解析。

// 单词类型
enum
{
   
   
	/*......其余类型......*/
    T_COMMA, T_LBRACKET, T_RBRACKET
};

// 扫描并返回在输入中找到的下一个单词。
// 如果标记有效则返回 1,如果没有标记则返回 0
int scan(struct token *t)
{
   
   
		/*......其他代码......*/
        case '[':   t->token = T_LBRACKET;  break;
        case ']':   t->token = T_RBRACKET;  break;
        /*......其他代码......*/
}

修改语法分析

修改了add_global()函数之后,也要在function_declaration()函数中修改

nameslot = add_global(Text, type, S_FUNCTION, endlabel, 0);

我们通过在var_declaration() 中查看下一个单词是什么来处理标量变量声明或数组声明:

// 分析变量声明
void var_declaration(int type)
{
   
   
    int id;
    if(type != P_INT)
    {
   
   
        fprintf(stderr, "Error token != T_INT on line %d\n", Line);
        exit(1);
    }
    while(1)
    {
   
   
        // 现在是标识符,如果下一个标记是"["
        if (Token.token == T_LBRACKET)
        {
   
   
            // 跳过"["
            scan(&Token);
            // 获得数组的大小
            if (Token.token == T_INT)
            {
   
   
                // 将此添加为已知数组并在汇编中生成其空间
                id = add_global(Text, P_INT, S_ARRAY, 0, Token.intvalue);
                arm_global_sym(id);
            }
            // 检查下一个"]"
            scan(&Token);
            match(T_RBRACKET, "]");
        }
        else
        {
   
   
            // 将其添加为已知标量并在汇编中生成其空间
            id = add_global(Text, P_INT, S_VARIABLE, 0, 1);
            // 如果下一个是"=",为变量赋初值
            if(Token.token == T_EQU)
            {
   
   
                scan
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值