将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,若都不是,则返回之前栈中所保存的数据,根据数据类型打印相关内容
- 将C语言的声明翻译成通俗的语言
- 将C语言的声明翻译成通俗语言——cdecl
- 把c语言中的声明用程序翻译成通俗的语言
- 编写一个程序,把C语言的声明翻译成通俗语言
- 能自动将软件翻译成不同语言的工具
- 一段汇编代码翻译成c语言的练习
- 将C语言的声明描述成为语言
- c语言的声明
- c语言的声明
- C语言的声明
- c语言的声明
- C语言的声明
- C语言的声明
- 奇怪的c语言声明
- 分析C语言的声明
- 分析C语言的声明
- 20100623--C语言的声明
- C语言声明的理解
- Python爬虫入门笔记:一个简单的爬虫架构
- VS中的路径宏 vc++中OutDir、ProjectDir、SolutionDir各种路径
- node.js + MongoDB + AngularJS - 4 事件、监听器、定时器、回调
- 运用腾讯云实现QQ语音通话
- HDU 4497 GCD and LCM (素数筛选+算术基本定理)
- 将C语言的声明翻译成通俗的语言
- Java 8 新特性:接口的静态方法和默认方法 ——诺诺"涂鸦"记忆
- C/C++自动生成makefile工具 supermake
- javascript常用数组算法总结
- maven自定义(修改)编译后输出的war或jar文件名
- HDOJ(HDU) 1859 最小长方形(水题、、)
- 使用Volley框架的ImageLoader加载大量网络图片的问题
- 盒子模型、块级元素与行内元素与内联元素
- ubuntu brackets中安装插件