• C专家编程 第3章 分析C语言的声明 3.8 理解所有分析过程的代码段


    /*主要的数据结构是一个堆栈,我们从左向右读取,把各个标记依次压入堆栈,直到读到标识符为止然后我们继续向右读入一个标记,也就是标识符右边的那个标记。接着,观察标识符左边的那个标记(需要从堆栈中弹出)。
     */ 
    struct token {
        char type; 
        char string[MAXTOKENLEN];
    };

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

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

    /*伪码如下:
    实用程序-------------*/
    classify_string(字符串分类)
        /*查看当前的标记,
         *通过this.type返回一个值,内容为"type"(类型),
         *"qualifier"(限定符)或"identifier"标识符 
         */
    gettoken(取标记);
    /*把下一个标记读入this.string
        *如果是字母数字组合,调用classify_string
        *否则,它必是一个单字符标记,this.type = 该标记;
        *用一个nul结束this.string 
        */
    read_to_first_identifier(读至第一个标识符)
        /*调用gettoken,并把标记压入到堆栈中,直到遇到第一个
         *标识符
         *Print"identifier is"(标识符是), this.string
         *继续调用gettoken
         */
    //解析程序 
    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 它是一个左括号'('
        将其弹出堆栈,并调用gettoken;应该获得右括号')' 
        deal_with_declarator
        else 将其弹出堆栈并打印它
    //主程序___________
    main
        read_to_first_identifier
        deal_with_declaration 

    #include
    #include
    #include
    #include
    #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_2;

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

    enum type_tag classify_string(void) 
    /*判断标识符的类型*/ 
    {
        char *s = this_2.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 gettoken(void) /*读取下一个标记到this_2*/
    {
        char *p = this_2.string;
        /*省略空白字符*/
        while ((*p = getchar()) == ' ');
        if (isalnum(*p)) {
            /*读入的标识符以A-Z或0-9开头*/
            while (isalnum(*++p = getchar()));
            ungetc(*p, stdin);
            *p = '\0';
            this_2.type = classify_string();
            return;
        }
        if (*p == '*') {
            strcpy(this_2.string, "pointer to");
            this_2.type = '*';
            return;
        }
        this_2.string[1] = '\0';
        this_2.type = *p;
        return;
    }

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

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

    void deal_with_function_args() {
        while(this_2.type != ')') {
            gettoken();
        }
        gettoken(); /*读取')'之后的再一个标记*/ 
        printf("function returning ");
    }

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

    deal_with_declarator() {
        /*处理标识符之后可能存在的数组/函数*/
        switch(this_2.type) {
            case '[': deal_with_arrays(); break;
            case '(': deal_with_function_args(); break;
        } 
        deal_with_pointers();
        /*处理在读入到标识符之前压入到堆栈中的符号*/
        while (top >= 0) {
            if (stack[top].type == '(') {
                pop;
                gettoken(); /*读取')'符号*/
                deal_with_declarator(); 
            } else {
                printf("%s ", pop.string);
            }
        } 
    }

    int main() {
        read_to_first_identifier();
        deal_with_declarator();
        printf("\n");
        return 0;
    }

    /* 输出:

    */ 

    /*小启发*/ 
    /*使字符串的比较看上去更自然
     *strcmp()函数用于比较两个字符串:它所存在的一个问题是:当两个字符串相等时函数的返回值
     *为零。当字符串比较是条件语句的一部分时,这个问题就是导致令人费解的代码:
     */ 
    if (!strcmp(s, "volatile")) return QUALIFIER;
    /*返回值零使条件语句的结果为假,所以我们不得不对其取反,得到需要的结果
     *这里有一个更好的办法
     */ 
    #define STRCMP(a, R, b) (strcmp(a, b) R 0)
    if (STRCMP(s, ==, "volatile"))

    Data Structures with Abstract Data Types
    这本书覆盖了范围很广的数据结构,包括字符串、列表、堆栈、队列、树,堆、集合和图。
    推荐大家阅读本书。 

  • 相关阅读:
    专业人士使用的 11 种渗透测试工具
    Qt实现右下角消息弹窗
    uniapp中 background-image 设置背景图片不展示问题
    Ubuntu18.04 实现:安装turtlebot3功能包、虚拟机与机器人之间的网络配置、测试机器人Cartographer建图
    面试总结之Spring篇
    JavaScript 严格模式
    当你离开现在的公司,你的百万业务量还能保持吗?
    Metronic 管理仪表板,高级引导仪表板主题
    SpringBoot整合Jpa实现增删改查功能(提供Gitee源码)
    视频编辑SDK测试
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126073122