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

来源:互联网 发布:mac display color 编辑:程序博客网 时间:2024/03/29 07:21

在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_stringread_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 64enum 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] = senum 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,若都不是,则返回之前栈中所保存的数据,根据数据类型打印相关内容

0 0
原创粉丝点击