将C语言的声明翻译成通俗的语言

在C语言中,有些声明看起来会十分晦涩。所以可以通过编写程序,将一些晦涩的声明翻译成通俗的语言。比如

char * (*c[10])(int **p);
char * const *(*next)();
...

对于声明,其中一个比较重要的成分是声明器,它是指标识符以及与它组合在一起的任何指针、函数括号、数组下标等。在声明中,包括类型说明符,存储类型,类型限定符。

类型说明符包括 : void、char、short、int、long、signed、unsigned、float、double、结构说明符(struct)、枚举说明符(enum)、联合说明符(union)

存储类型包括 : extern、static、register、auto、typedef

类型限定符包括 : const、volatile

了解这些概念之后,开始编写程序。

这里有个设计方案,主要的数据结构是一个堆栈,我们从左向右读取,把各个标记依次压入堆栈,直到读取标识符为止。然后我们继续向右读入一个标记,也就是标识符右边的那个标识。接着,观察标识符左边的那个标记(需要从堆栈中弹出)。

数据结构大致如下:
struct token 
{
    char type;
    char string[MAXTOKENLEN];
};

/* 保存第一个标识之前的所有标识  */
struct token stack[MAXTOKENS]; 

/* 保存刚读入的那个标识 */
struct token this; 


//先在这里列出大致的伪代码
实用程序------
classify_string (字符串分类)
    查看当前的标记
    通过this.type返回一个值,内容为"type(类型)""qualifier(限定符")    
    或"indentifier(标识符)"
get_token(取标记)
把下一个标记读入this.string
    如果是字母数字组合,调用classify_string
    否则必是一个单字符标记,this.type = 该标记;用NUL结束this_string
read_to_first_identifier(读至第一个标识符)
    调用get_token,并把标记压入到堆栈中,直到遇见第一个标识符
    Print "identifier is (标识符是) this.string"
    继续调用get_token

解析程序------
deal_with_function_args(处理函数参数)
    当读取越过右括号')'后,打印"函数返回"
deal_with_arrays(处理函数数组)
    当读取"[size]"后,将其打印并继续向右读取
deal_with_any_pointers(处理任何指针)
    当从堆栈中读取"*"时,打印"指向...的指针"并将其弹出堆栈
deal_with_declarator(处理声明器)
    if this.type is '['  deal_with_arrays
    if this.type is '('  deal_with_function_args
    deal_with_any_pointers
    while 堆栈里还有东西
    if 它是一个左括号 '('
    将其弹出堆栈,并调用get_token; 应该获得右括号')'
    deal_with_declarator
    else 将其弹出堆栈并打印它

以下是程序代码,为了简单方便起见,对于函数的参数不作处理:

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAXTOKENS 100
#define MAXTOKENLEN 64

enum type_tag { IDENTIFIER, QUALIFIER, TYPE };  /* 标识符,限定符,类型 */ 

struct token 
{
    char type;
    char string[MAXTOKENLEN];
};

int top = -1;

/* 保存第一个标识之前的所有标识  */
struct token stack[MAXTOKENS]; 

/* 保存刚读入的那个标识 */
struct token this; 

#define pop stack[top--]
#define push(s) stack[++top] = s

enum type_tag classify_string (void)  /* 推断标识符的类型 */ 
{
    char *s = this.string;
    if (!strcmp (s, "const"))
    {
        strcpy (s, "read-only");
        return QUALIFIER;
    }   
    if (!strcmp (s, "volatile"))
        return QUALIFIER;

    if (!strcmp (s, "void"))
        return TYPE;
    if (!strcmp (s, "char"))
        return TYPE;
    if (!strcmp (s, "signed"))
        return TYPE;
    if (!strcmp (s, "unsigned"))
        return TYPE;
    if (!strcmp (s, "short"))
        return TYPE;
    if (!strcmp (s, "int"))
        return TYPE;
    if (!strcmp (s, "long"))
        return TYPE;
    if (!strcmp (s, "float"))
        return TYPE;
    if (!strcmp (s, "double"))
        return TYPE;
    if (!strcmp (s, "struct"))
        return TYPE;
    if (!strcmp (s, "union"))
        return TYPE;
    if (!strcmp (s, "enum"))
        return TYPE;

    return IDENTIFIER;
} 

void get_token(void)  /* 读取下一个标识到this */ 
{
    char *p = this.string;

    /* 略过空白字符 */
    while ((*p = getchar()) == ' ')
        continue;

    if (isalnum (*p))  /* 读入的标识符是以a-z, A-Z, 0-9开头 */ 
    {

        while (isalnum (*++p = getchar()))  /* 一直读,直到读到的字符不是a-z, A-Z, 0-9 */ 
            continue;   
        ungetc (*p, stdin);  /* 将最后读到的那个不是 a-z, A-Z, 0-9 的字符退回到输入流中 */
        *p = '\0';
        this.type = classify_string();
        return; 
    }   

    if (*p == '*')
    {
        strcpy (this.string, "pointer to");
        this.type = '*';
        return;
    }

    this.string[1] = '\0';
    this.type = *p;
    return;
}

/* 理解所有分析过程的代码段 */ 
void read_to_first_identifier(void)
{
    get_token();    
    while (this.type != IDENTIFIER)
    {
        push (this);
        get_token();
    }
    printf ("%s is ", this.string);
    get_token();
}

void deal_with_arrays(void)
{
    while (this.type == '[')
    {
        printf ("array ");
        get_token();  /* 数字或']' */
        if (isdigit (this.string[0]))
        {
            printf ("0..%d ", atoi(this.string) - 1);
            get_token();  /* 读取']' */ 
        } 
        get_token();  /* 读取']' 之后的再一个标记 */
        printf ("of "); 
    }
}

void deal_with_function_args()
{
    while (this.type != ')')
    {
        get_token();
    }
    get_token();
    printf ("function returning ");
}

void deal_with_pointers()
{
    while (stack[top].type == '*')
        printf ("%s ", pop.string);
}

void deal_with_declarator(void)
{
    /* 处理标识符之后可能存在的数组/函数 */
    switch (this.type)
    {
        case '[' : deal_with_arrays(); 
                   break;
        case '(' : deal_with_function_args();
                   break;
    } 

    deal_with_pointers();

    /* 处理在读入到标识符之前压入到堆栈中的符号 */ 
    while (top >= 0)
    {
        if (stack[top].type == '(')
        {
            pop;
            get_token();    /* 读取')'之后的符号 */
            deal_with_declarator(); 
        }
        else
        {
            printf ("%s ", pop.string);
        }
    }

} 

int main(void)
{
    /* 将堆栈压入堆栈中,直到遇见标识符 */
    read_to_first_identifier();
    deal_with_declarator();
    printf ("\n");
    return 0; 
}

对于该程序,整个的思路是这样:
1. 读取输入的字符串,比如 char * ( * c[10])( int ** p)。读取函数是read_to_first_identifier,具体的读取函数是get_token,该函数会返回读取的枚举类型,若不等于IDENTIFIER,则会一直读,同时将不等于IDENTIFIER的压入栈中。
2. 当读到整个标识符时,将继续读取它的下一位,用于处理标识符之后可能存在的数组或函数。若是[字符,则执行函数deal_with_arrays,若是(字符,则执行函数deal_with_function_args,若都不是,则返回之前栈中所保存的数据,根据数据类型打印相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值