100 Days of Code-day37-“解密”

100 Days of Code-day37-“解密”,第1张

程序dcl根据声明符的语法对声明进行分析,通过递归调用两个函数来讲C语言的声明转换为文字叙述。

dcl程序是基于对声明符的语法进行详细描述。

dcl : 前面带有可选的*的 direct-dcl
direct-dcl: name
(dcl)
direct-dcl()
direct-dcl[可选的长度]

反思:out[0] = ‘\0’;的重要性

虽然在第一次将声明转换为文字描述时,这行语句没有意义。因为静态数组在没有认为定义的情况下,会自动将其各元素设置为’\0’
但是,当我们进行第二次转换时,第一次的声明还储存在out数组中,这不是我们所需要的。因为strcat函数只会找到该数组中的终止符位置,将字符串常量scr追加到目标字符串dest,将目标字符的终止符覆盖掉,然后在添加一个终止符位。
以下为相关结果显示:

没有out[0] = '\0’语句

添加out[0] = '\0’语句后:

完整程序及其解释:
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include

#define MAXTOKEN 100

enum{NAME, PARENS, BRACKETS};
//NAME是变量名的标志  PARENS是圆括号的标志 BRACKETS是方括号的标志

void dcl(void);
void dirdcl(void);
int gettoken(void);
int tokentype;			//最后一个记号的类型
char token[MAXTOKEN];	//最后一个记号字符串(后读取的记号字符串会覆盖掉之前读取的)
char name[MAXTOKEN];	//标识符名
char datatype[MAXTOKEN];//数据类型为char,int等
char out[100];			//输出串

//将声明转化为文字描述
int main()
{
	while (gettoken() != EOF) {		//该行的第一个记号是数据类型,输入的正确声明中
		strcpy(datatype, token);	//tokentype=NAME时,刚开始就是数据类型,接下来就是变量名(name)
		out[0] = ';'dcl		
		();//分析该行的其余部分,主函数的调用暂时中止		if
		( !=tokentype '\n' )printf
			("syntax error\n");printf
		("%s: %s %s\n",, name, out) datatype;//由此我们发现声明的文字叙述可以分为3部分:变量名,待分析部分,数据类型	
		//在该例子中将这三个部分分开放入各自数组中进行处理
		}
//变量名和数据类型部分的位置是固定的,分别在最前面和最后面		system
	("pause");return
	0 ;}
//dcl(declaration):对一个声明符进行语法分析

void
dcl (void)int
{
	; ns//在判断是否为直接声明时,先看一下其前面是否有解引用运算符(通过指针间接访问)
	for
	( =ns 0 ;gettoken ()== '*' ;)//统计字符'*'的个数	++
		ns;dirdcl
	();while		
	( --ns0 > )//跳出dirdcl函数,就表明对于全部或者圆括号内(部分)的直接声明来说	strcat
		(,out" pointer to" );//我们已经将其分析好了,那么接下来就可一个先将“指向(直接声明)”的字样存储进来	}
//分析直接声明,通过gettoken函数返回代表记号类型的值,来进行相应的语法分析

void
dirdcl (void)//根据前面提供的语法可知,直接声明简单来说分为//以“字母”开头的变量名
//通过圆括号,嵌套一个声明dcl(以字符“(”开头)
//变量名+“()”or"[]"(以“字母”开头的变量名)
//所以当直接声明不以"("或者“变量名”开头,那么输入内容就是有问题的
{
int
	; typeif

	( ==tokentype '(' )//如果有左括号就需要再次判断圆括号中是否有'*'运算符 {		dcl
		();//在分析完圆括号中的内容后,返回到之前被递归调用打断的部分		if
		( !=tokentype ')' )//如果此时接下来的记号不是右括号,那么需要报错printf
			("error:missing  )\n");}
	else
	if ( ==tokentype ) NAME//若第二次返回该记号类型,表明其为变量名,则将其放入name数组中	strcpy
		(,name) token;else
	printf
		("error: expected name or (dcl)\n");while
	( (=type gettoken ())== || PARENS == type ) BRACKETSif
		( ==type ) PARENSstrcat
			(,out"function returning" );else
		//当返回的记号类型为方括号时,表明对于声明的文字描述中要有“array[size] of”字样的出现 {		strcat
			(,out" array" );strcat
			(,out) token;strcat
			(,out" of" );}
		}
int

gettoken (void)//返回下一个标记	int
{
	, cgetch (void);void
	ungetch (int);char
	* =p ; tokenwhile

	( (=c getch ())== ' ' || == c '\t' );
		if
	( ==c '(' )if {
		( (=c getch ())== ')' )strcpy {
			(,token"()" );return
			= tokentype ; PARENS}
		else
		//如果左括号和有括号之间有内容,则需要先将多入的字符保存起来,对其里面的内容进行分析 {		ungetch
			()c;return
			= tokentype '(' ;}
		}
	else
	if (==c'[')for{
		( *++p= ; c( *++p= getch ())!= ']' ;)//在遇到左方括号时,一直读取内容直到右方括号的出现	;
			*
		=p ';' return=
		; tokentype } BRACKETSelse
	if
	( isalpha ())c//判断字符c是否为大写字母或小写字母for {		(
		* ++=p; isalnum c( =getchc ( ));)//在将字符放入token数组后,再次判断下一个字符*		++
			=p; //是否为字母或是数字 c*								=
		';'p ungetch ()
		;//为了保证读取内容的完整性,往往要多读取一个字符。为了保证不遗漏掉多读取的内容c//需要将其临时存储在一段空间中return		=
						;
		} tokentype else NAMEreturn
	=
	;  } tokentype # cdefine
BufSize

100int [ ]

; BufintBufSize*=
; //下一个空闲位置bufp int Bufgetch(

void )return?*
{
	-- bufp > Buf : getchar(bufp ) ;}voidungetch
(

int )if( c<
{
	+ )bufp * Buf ++ BufSize=
		;bufpelse printf c(
	"buffer is full"
		);}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1498105.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-25
下一篇 2022-06-25

发表评论

登录后才能评论

评论列表(0条)

保存