程序实现分析C语言的声明语句含义

本程序参考了《C专家编程》一书中第3章“分析C语言的声明”中图3-1(65页)以及71页、72页的伪代码实现。程序能完成基本分析功能。如有问题,欢迎给我留言讨论。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#define MAXTOKENLEN 20
#define STACKLEN 20
#define STRINGSIZE 20


#define QUALIFIER 'q'
#define IDENTIFIER 'i'
#define TYPE 't'


/**
 **函数实现:通过程序分析C语言中的声明,尤其是函数、数组、指针等混在一起的复杂形式
 **比如:int ( * fun ( ) ) ( ) ; 或者 char * const * ( * next ) ( ) ; 等
 */


/**

 **其中,读入的符号分为三种类型:类型符,如int等;限定符,如*,const,volatile等;标识符,就是名字字符串。


 **第一步:我们自左向右读取,将所有标记压入堆栈,直到标识符为止。


 **第二步:读入标识符右边的符号。如果是方括号,将[可能的大小]读完,输出“……的数组”;


 **第三步:如果是左括号,将(可能的参数)读完,即直到右括号为止,输出“返回……的函数”。


 **第四步:如果左边的符号(堆栈中的那个符号)是一个左括号,一直读,直到遇见对应的右括号,然后跳到第二步;


 **第五步:如果左边的符号是const,volatile,*之一:如果是const,输出”只读“;如果是volatile,输出”volatile“;
 **如果是*,输出”指向……的指针“。继续向左边读(即出栈),直到所读符号不再是三者之一,然后重复第四步。


 **第六步:将堆栈中剩下的符号形成声明的基本类型。
 */


struct token
{
    char type; //符号的类型
    char string[STRINGSIZE]; //符号名字
};


struct token stack[STACKLEN]; //符号堆栈
struct token present; //用来保存刚刚读入那个符号
int top = -1; //指向栈顶元素


/**对读入的token进行分类,包括标识符identifier、类型type和限定符qualifier*/
char token_classify(char *string)
{
    if(strcmp(string,"const") == 0 || strcmp(string,"volatile") == 0 || strcmp(string,"*") == 0) //如果是限定符
        return QUALIFIER;
    else if(strcmp(string,"int") == 0 || strcmp(string,"long") == 0 || strcmp(string,"short") == 0 ||
            strcmp(string,"double") == 0 || strcmp(string,"unsigned") == 0 || strcmp(string,"float") == 0 ||
            strcmp(string,"char") == 0 || strcmp(string,"enum") == 0 || strcmp(string,"union") == 0 ||
            strcmp(string,"struct") == 0 || strcmp(string,"void") == 0) //如果是类型符
            return TYPE;
    else if(strcmp(string,"(") == 0 || strcmp(string,")") == 0) //对于'('和')'单独处理
        return ' ';
    else //排除其他情况后,剩余标识符
        return IDENTIFIER;
}


/**读入下一个字符或字符串,并调用分类函数进行分类处理*/
void get_token()
{
   char *p = present.string; 读入后暂存在present当前符号变量中,指针指向present.string
   while((*p = getchar()) == ' '); //跳过空格
   if(isalnum(*p)) //如果是字母或数字
   {
       while(isalnum(*p))
       {
           *++p = getchar();
       }
       ungetc(*p,stdin); //退回非字母或数字的那个符号,用于下次读入
   }
   else
   {
       p++; //如果是其他符号,比如'('')''*'直接读入
   }
   *p = '\0'; //加上字符串结束标志
   present.type = token_classify(present.string); //分类
}


/**读至标识符,从左至用入栈,并显示标识符内容,第一步*/
void read_to_first_identifier()
{
    get_token();
    while(present.type != IDENTIFIER) //如果没读到标识符,将之前左边的符号全部入栈
    {
        top++;
        stack[top] = present;
        get_token();
    }
    printf("标识符是%s,",present.string); //输出标识符名字
    get_token();
}


/**处理数组,第二步*/
void deal_with_arrays()
{
    while(present.string[0] != ']') //如果还没读到匹配的']',继续读,这样就将数组大小读入并忽略了
        get_token();
    printf("数组,该数组类型是"); //读到后输出它是一个数组
    get_token();
}


/**处理函数,第三步*/
void deal_with_functions()
{
    while(strcmp(present.string,")") != 0) //如果还没读到匹配的')',继续读,这样就将函数的参数都读入并忽略了
        get_token();
    printf("函数,该函数返回"); //读到后输出它是一个函数
    get_token();
}


/**处理限定符,第五步*/
void deal_with_qualifiers(char *string) //限定符有三类,根据名字分别处理
{
    if(strcmp(string,"const") == 0) //输出只读
        printf("只读");
    else if(strcmp(string,"*") == 0) //输出它是一个指针
        printf("指针,这个指针指向");
    else
        printf("volatile"); //输出volatile
}


/**处理声明器,第二步,第三步,第四步,第五步,第六步*/
void deal_with_all()
{
    struct token temp;
    //第2步
    step2:
    if(strcmp(present.string,"[") == 0) //标识符右边,如果是'[',作为数组处理
        deal_with_arrays();
    //第3步
    else if(strcmp(present.string,"(") == 0) //标识符右边,如果是'(',作为函数处理
        deal_with_functions();
    //第4步
    step4:
    temp = stack[top--]; //取栈顶元素,即标识符左边符号
    if(strcmp(temp.string,"(") == 0) //如果是'(',读到标识符右边')'为止
    {
        while(strcmp(present.string,")") != 0)
            get_token();
        get_token();
        goto step2; //跳到第2步
    }
    //第5步
    else if(temp.type == QUALIFIER) //如果标识符左边符号是三个限定符之一
    {
        deal_with_qualifiers(temp.string); //输出限定符代表的输出
        while(stack[top].type == QUALIFIER) //获得堆栈中下一元素,如果仍为限定符继续输出知道不是限定符为止
        {
            deal_with_qualifiers(stack[top].string);
            top--;
        }
        goto step4; //跳到第4步
    }
    //第6步
    else if(temp.type == TYPE) //将剩下的符号作为声明的基本类型输出
    {
        printf("%s",temp.string);
    }
}


int main()
{
    read_to_first_identifier();
    deal_with_all();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值