简易C语言声明解析器(cdecl)——C语言实现

1 什么是cdecl

cdecl是C语言声明的简称,通俗来讲就是把C语言的声明翻译成通俗语言。

2 代码

本程序暂时没有考虑错误处理,而且在处理结构、枚举和联合时只简单地用“struct”,“enum”,“union”来代表它们的具体内容。最后,这个程序假定函数的括号内没有参数列表。

# 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 gettoken(void){
   
    /* 读取下一个标记到this */
    char *p = this.string;

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

    if(isalnum(*p)){
   
        /* 读入的标识符以A-Z, 0-9开头 */
        while(isalnum(*++p = getchar()));
        ungetc(*p, stdin);
        *p = '\0';
        this.type = classify_string();
        return;
    }

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

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

/* 理解所有分析过程的代码段 */
void read_to_first_identifer(){
   
    gettoken();
    while(this.type != IDENTIFIER){
   
        push(this);
        gettoken();
    }
    printf("%s is ", this.string); //打印标识符
    gettoken();
}

void deal_with_array() {
   
    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_array();break;
        case '(': deal_with_function_args();
    }

    deal_with_pointers();

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

int main() {
   
    //将标记压入堆栈中,直到遇见标识符
    printf("Please enter a C declaration: ");
    read_to_first_identifer();
    deal_with_declarator();
    printf("\n");
    return 0;
}

/*
输出示例:
Please enter a C declaration: int (*func)()
func is pointer to function returning int

Please enter a C declaration: int *(*a[3])();
a is array 0..2 of pointer to function returning pointer to int

Please enter a C declaration: struct pm i;
pm is struct
*/

3 基本思路

设计方案是弄一个堆栈,从输入流中依次向右读取,把各个标记依次压入堆栈,直到读到标识符为止。然后继续向右读入一个标记,也就是标识符右边的那个标记。接着,观察标识符左边的那个标记(需要从堆栈中弹出)。


写在最后

本文是博主阅读《C专家编程》时的摘录,为了日后方便理解复习C声明的知识,特意作此文章,同时也希望可以帮到各位,Thank you very much!

相关推荐

  1. 简易C语言声明解析(cdecl)——C语言实现

    2023-12-16 22:24:01       45 阅读
  2. C语言 数组声明

    2023-12-16 22:24:01       15 阅读
  3. c语言之函数声明

    2023-12-16 22:24:01       24 阅读
  4. C语言如何声明外部变量?

    2023-12-16 22:24:01       15 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-16 22:24:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-16 22:24:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-16 22:24:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-16 22:24:01       18 阅读

热门阅读

  1. docker的资源控制

    2023-12-16 22:24:01       26 阅读
  2. centos 安装 Imagick 执行转换为 图片报错

    2023-12-16 22:24:01       37 阅读
  3. Redis部署文档

    2023-12-16 22:24:01       36 阅读
  4. 考研真题C语言

    2023-12-16 22:24:01       50 阅读
  5. git变更关联的远程仓库

    2023-12-16 22:24:01       41 阅读
  6. springboot项目当中分库分表

    2023-12-16 22:24:01       45 阅读
  7. 汽车IC芯片

    2023-12-16 22:24:01       39 阅读
  8. .QT信号槽,如何同步异步?

    2023-12-16 22:24:01       38 阅读
  9. 代码随想录——链表 刷题记录

    2023-12-16 22:24:01       43 阅读
  10. arcgis api for js 中的query实现数据查询

    2023-12-16 22:24:01       40 阅读