• C专家编程cdecl


    理解所有分析过程的代码段

    Page71(中文版)
    你可以轻松地编写一个能够分析C语言的声明并把他们翻译成通俗语言的程序。事实上,为什么不?C语言声明的基本形式已经描述清楚。我们所需要的只是编写一段能够理解声明的形式并能够以图3-3的方式对声明进行分析的代码。为了简单起见,暂且忽略错误处理,而且在处理结构、枚举和联合时只简单地用"struct", "enum"和"union"来代表它们的具体内容。最后,这个程序假定函数的括号内没有参数列表

    • 编程挑战

    编写一个程序,把C语言的声明翻译成通俗语言

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

    struct token { 
        char type;
        char string[MAXTOKENLEN];
    };
    /* 保存第一个标识之前的所有标记 */
    struct token stack[MAXTOKENS];
    
    /* 保存刚读入的那个标记 */
    struct token this;
    
    伪码如下:
    实用程序------------
    classify_string(字符串分类)
        查看当前的标记
        通过this.type返回一个值,内容为"type(类型)", "qualifier(限定符)"或"indertifier(标识符)"
        
    gettoken(取标记)
    把下一个标记读入this.string
        如果是字母数字组合,调用classify_string
        否则,它必是一个单字符标记,this.type = 该标记;用一个nul结束this.string
        
    read_to_first_identifier()
        调用gettoken,并把标记压入到堆栈中,直到遇见第一个标识符。
        Print"identifier is (标识符是)", this.string
        继续调用gettoken
        
    解析程序-----------
    
    deal_with_fuction_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_declarator
        
    
    

    这是一个小型程序,在过去的几年中已被编写过无数次,通常取名为"cdecl". The C Programming Language有一个cdecl的不完整版本,本书的cdecl程序则更为详尽。它支持类型限定符const和volatile。同时它还涉及结构、枚举和联合,尽管在这方面做了简化。你可以轻松地用这个版本的程序来处理函数中的参数声明。这个程序可以用大约150行C代码实现。如果加入错误吹,并使程序能够处理的声明范围更广一些,程序就会更长一些。无论如何,当编制这个解析器时,相当于正在实现编译器中主要的子系统之一----这是一个相当了不起的编程成就,能够帮助你获得对这个领域的深刻理解。

    更多的阅读材料

    既然已经精通了在C语言中创建数据结构的方法,可能会对那些讲述通用目的的数据结构书感兴趣。其中一本是Data Structures with Abstract Data Types, Daniel F.Stubb和Neil W.Webre著,第二版,Pacific Grove, CA, Brooks/Cole, 1989.
    这本书覆盖了范围很广的数据结构,包括字符串、列表、堆栈、队列、树、堆、集合和图。我推荐此书。

        #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") == 0) {
                strcpy(s, "read-only");
                return QUALIFIER;
            }
            
            if (strcmp(s, "volatile") == 0) {
                return QUALIFIER; 
            }
            if (strcmp(s, "void") == 0) {
                return TYPE; 
            }
            if (strcmp(s, "char") == 0) {
                return TYPE;
            }
            if (strcmp(s, "signed") == 0) {
                return TYPE;
            }
            if (strcmp(s, "unsigned") == 0) {
                return TYPE;
            }
            if (strcmp(s, "short") == 0) {
                return TYPE;
            }
            if (strcmp(s, "int") == 0) {
                return TYPE;
            }
            if (strcmp(s, "long") == 0) {
                return TYPE;
            }
            if (strcmp(s, "float") == 0) {
                return TYPE;
            }
            if (strcmp(s, "double") == 0) {
                return TYPE;
            }
            if (strcmp(s, "struct") == 0) {
                return TYPE;
            }
            if (strcmp(s, "union") == 0) {
                return TYPE;
            }
            if (strcmp(s, "enum") == 0) {
                return TYPE;
            }
            
            return INDENTIFIER;
        }
      
      /* 读取下一个标记到"this" */ 
       void gettoken(void)
       {
            char *p = this.string;
            /* 略过空白字符 */
            while((*p = getchar()) == ' ') {
                ;
            }
           
           /* 读入的标识符以A-Z, 0-9开头 */ 
            if (isalnum(*p)) {
                 while( isalnum(*++p = getchar()) ) {
                    ; 
                 }
                 
                 ungetc(*p, stdin);
                 *p = '';
                 this.type = classify_string();
                 return ;
            }
            if ( *p == '*' ) {
                strcpy(this.string, "pointer to ");
                this.type = '*';
                return;
            }
            
            this.string[1] = '';
            this.type = *p;
            return;
       }
       /* 理解所有分析过程的代码段 */
       void read_to_first_identifer() {
            gettoken();
            while( this.type != IDENTIFIER ) {
                push(this);
                gettoken();
            }
            printf("%s is ", this.string);
            gettoken();
        }
        
        void deal_with_arrays() {
            while( this.type == '[') {
                printf("array ");
                gettoken(); /* 数字或 ']' */
                if (isdigit(this.string[0])) {
                    printf("0..%d ", atoi(this.string)-1 );
                    gettoken(); /* 读取']' */
                }
                gettoken(); /* 读取']'之后的再一个标记 */
                printf("of ");
            }
        }
        void deal_with_function_args() {
            while(this.type != ')' ) {
                gettoken();
            }
            gettoken();
            printf("function returning ");
        }
        
        void deal_with_pointers() {
            while(stack[top].type == '*') {
                printf("%s ", pop.string);
            }
        }
       
       /* 处理标识符之后可能存在的数组/函数 */ 
        void deal_with_declarator() {
            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;
                    gettoken(); /* 读取')'之后的符号 */
                    deal_with_declarator();
                }
                else {
                    printf("%s ", pop.string);
                }
            }
        }
        
        int main()
        {
            /* 将标记压入堆栈中,直到遇见标识符 */ 
            read_to_first_identifier();
            deal_with_declarator();
            printf("
    ");
            return 0;
        }
    
    转载本Blog文章请注明出处,否则,本作者保留追究其法律责任的权利。 本人转载别人或者copy别人的博客内容的部分,会尽量附上原文出处,仅供学习交流之用,如有侵权,联系立删。
  • 相关阅读:
    XML之四种解析dom,sax,jdom,dom4j原理及性能比较
    uni-app 下小程序bindgetuserinfo不回调原因
    微信小程序 -- 真机不打开调试无法正常使用小程序的坑
    如何申请腾讯位置服务的密钥
    使用Promise封装小程序wx.request的实现方法
    关于vue-router当中addRoutes的使用
    前端Promise总结笔记
    css怎么设置超出几行显示省略号?
    大数据Spark和Hadoop以及区别(干货)
    Spark和Hadoop的区别和比较
  • 原文地址:https://www.cnblogs.com/drfxiaoliuzi/p/4896465.html
Copyright © 2020-2023  润新知