编译原理 递归下降语法分析程序

老师要求做的一个课设,但是。网上很多都不是递归下降的。

在理解编译原理基本思想的基础上,选择一个自己熟悉的程序设计语言,完成编译程序的设计和实现过程。

编译程序的设计可以采用自顶向下和自底向上两种不同的方法。由于许多高级语言(如PASCAL,C)中的语法成分都是递归定义的,所以本实验要求学生采用递归下降分析技术,这是一种自顶向下的的编译方法,其基本思想是对语言的每个(或若干个)语法成分编制一个处理子程序,从处理<程序>这个语法成分的子程序开始,在分析过程中调用一系列过程或函数,对源程序进行语法和语义分析,直到整个源程序处理完毕为止。

本上机实习是为C语言(子集)设计一个编译程序,完成词法分析、语法分析、语义分析等功能,并生成某种机器上的目标代码(汇编语言)或中间代码(四元式)。

这是老师的要求

2、C语言小子集的文法规则:

<程序>::=main(){<分程序>}

       <分程序>::=<变量说明部分>;<语句部分>

       <变量说明部分>::=<变量说明><标识符表>

<变量说明>::=int

<标识符表>::=<标识符表>,<标识符>

<标识符表>::=<标识符>

       <标识符>::=<字母>

<标识符>::=<标识符><字母>

<标识符>::=<标识符><数字>

       <语句部分>::=<语句部分><语句>;|<语句>;

<语句>::=<赋值语句>|<条件语句>|<循环语句>|

<赋值语句>::=<标识符>=<表达式>

       <条件>::=<表达式><关系运算符><表达式>

       <表达式>::=<项>|<表达式><加法运算符><项>

<项>::=<因子>|<项><乘法运算符><因子>

<因子>::=<标识符>|<常量>|(<表达式>)

<常量>::=<无符号整数>

<无符号整数>::=<数字序列>

<数字序列>::=<数字序列><数字>

<数字序列>::=<数字>

<加法运算符>::=+|-

<乘法运算符>::=*|/

<关系运算符>::=<|>|!=|>=|<=|==

<复合语句>::={<语句部分>}

<语句1>::=<语句>|<复合语句>

<条件语句>::=if(<条件>)<语句1>else<语句1>

<循环语句>::=while(<条件>)do<语句1>

<字母>::=a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z

<数字>::=0|1|2|3|4|5|6|7|8|9

输入源程序样本:(这只是一个例子,调试时可以任意修改或换其它程序)

main ()
{ int a,x,b,y,max;
a=10;  b=12;
while  (a<0) 
{ b=a+b*a;
a=a-1
};
x=a+b;  y=b+b;
if  (x>y)  max=x;
else max=y;
}

下面直接给代码(代码有点长,700行左右)

#include<stdio.h>
#include<sstream>
#include<iostream>
#include<stdlib.h>
#include<fstream>
#include<string.h>
#include<math.h>
#include<cstring>
#include <vector>
#include<iomanip>

using namespace std;
char const *keyword[7] = { "if", "else", "for", "while", "do", "int", "main"}; //关键字

class Word           //单词表类 
{ 
	public:
	char value[20];//单词自身的值 
	int type;//单词的种别(10标识符,20常数,30关键字,4-运算符(加法运算符为41,乘法为42,关系运算符43),50界符) 
	int line;//行号
};

class Genq  //四元式 
{
	public:
	string op;  //算符 
	string data1;//操作数1 
	string data2;//操作数2 
	string res; //结果 
};
 
FILE *fin,*fout;//文件流 
int line=1;	//单词所在行数 
char buff[10];//存放单词的数组 
int flag=0;//词法分析判断是否已经从文件流中获取字符 
Word new_w;
Genq four[100];//用数组表示类对象四元式 

int f_num=0;//四元式个数
int e;//错误次数 
char ch;//字符流中获取的字符 
int flag1,flag2=0;
string ys[100];//已经声明的变量 
int y_num=0;//已经声明变量的个数 
string op;  //算符 
string str1;//操作数1 
string str2;//操作数2 
string result; //结果
int f=0; //表达式中运算符的个数 
int aaa;  
int tj_x;//记录while和if条件的四元式的序号 
string a[200];
string a2;
string a3;
int a_num=1;

void P();//程序
int A(); //(){分程序}
void B();//分程序
void C();//变量说明部分
int F();//标识符表
int F1();//标识符
void D();//语句部分
int D1();//子语句部分
int H();//语句
int I();//赋值语句
int Q();//表达式
int X();//项 
int X1();//子项
int Q1(); //子表达式
int Y();//因子 
int J();//条件语句 
void K();//循环语句
int H1();//语句1
int TJ();//条件

void makeFour(string op,string d1,string d2,string r)//构造四元式 
{	
	four[f_num].op=op;
	four[f_num].data1=d1;
	four[f_num].data2=d2;
	four[f_num].res=r;
	f_num++;
}
void printFour()//输出四元式 
{
	ofstream out("ygro.txt");
    int i;
    for(i=0;i<f_num;i++)
   {
   	  cout<<i<<":\t("<<four[i].op<<",\t"<<four[i].data1<<",\t"<<four[i].data2<<",\t"<<four[i].res<<")"<<endl;
   	  
   	  out<<i<<":\t("<<four[i].op<<",\t"<<four[i].data1<<",\t"<<four[i].data2<<",\t"<<four[i].res<<")"<<endl;
   }
}
void error(char doc[])//报错,定位到错误行 
{
        cout<<"第"<<new_w.line<<"行出错!\t";
		cout<<doc<<"\n";
		e++;
}
void ise(string a)  //检查变量是否被声明
{
	int i;
    for(i=1;i<=y_num;i++)
    {
    	if(a.compare(ys[i])==0)
		{
			break;
		}
	}
	if(i>y_num)  
	{
		cout<<"第 "<<new_w.line<<" 行出错!\t";
		cout<<new_w.value<<" 没有被声明 !"<<endl;
		e++;
	}
}
int getWord()//词法分析 
{
	int i=0; //buff当前字符的位置 
	int j=0; //new_w当前字符的位置 
	if(flag==0)
	{
		ch=getc(fin);
	}
	while(ch==' '||ch=='\n'||ch=='\t')//识别空格,换行,和tab
	{
		if(ch=='\n')
		{	 
			line++;//行+1 
		}
		ch=getc(fin);
		flag=1;
	} 
	if(ch>='a'&&ch<='z')//识别字母开头的变量或者单词; 
	{
		for(i=0;i<10;i++)
		{
			buff[i]=NULL;
		}i=0;
	
		do{
			buff[i++]=ch;  //吧字符流中的字符放到buff中 
			ch=getc(fin);
			flag=1;
		}while((ch>='a' && ch<='z') || (ch>='0' && ch<='9')); 
		strcpy(new_w.value,buff);//把buff的值放到单词表 
		new_w.line=line;//行数 
		int n;
		for(n=0;n<7;n++)
		{
			if(strcmp(new_w.value,keyword[n])==0)//判断是不是关键字 
			break;
		}
		if(n<7)//是关键字 
		{
			new_w.type=30;//关键字类型为03 
		}else{
			new_w.type=10;//标识符类型为01 
		}
	return 0;
	}
	else if(ch>='0' && ch<='9')
	{
		for(i=0;i<10;i++)
		{
			buff[i]=NULL;
		}i=0;
		do{
			buff[i++]=ch;
			ch=getc(fin);
			flag=1;	
		}while(ch>='0' && ch<='9');
		strcpy(new_w.value,buff);
		new_w.type=20;//数字类型为02 
		new_w.line=line;
		
		//***************************
	//	cout<<new_w.value;
	return 0;
	}
	else if(ch=='+' || ch=='-')
	{	
		for(i=0;i<10;i++)
		{
			buff[i]=NULL;
		}i=0;
		buff[i++]=ch;
		ch=getc(fin);
		flag=1;	
		strcpy(new_w.value,buff);
		new_w.type=41;	//加法运算符 
		new_w.line=line;
		
		//**************************
	//	cout<<new_w.value;
	return 0;
	}
	else if(ch=='*'||ch=='/')
	{
		for(i=0;i<10;i++)
		{
			buff[i]=NULL;
		}i=0;
		buff[i++]=ch;
		ch=getc(fin);
		flag=1;	
		strcpy(new_w.value,buff);
		new_w.type=42;	//乘法运算符 
		new_w.line=line;
		
		//**************************
	//	cout<<new_w.value;
	return 0;
	}
	else if(ch=='='||ch=='<'||ch=='>'||ch=='!')
	{	
		for(i=0;i<10;i++)
		{
			buff[i]=NULL;
		}
		i=0;
		buff[i++]=ch;
		ch=getc(fin);
		flag=1;	
		if(ch=='=')
		{
			buff[i++]=ch;
			ch=getc(fin);
			flag=1;	
		}
		strcpy(new_w.value,buff);
		new_w.type=43;	//关系运算符 
		new_w.line=line;
		
		//**************************
	//	cout<<new_w.value;
	return 0;
	}
	else if(ch==','||ch==';'||ch=='('||ch==')'||ch=='{'||ch=='}')
	{
	   	for(i=0;i<10;i++)
		{
			buff[i]=NULL;
		}
		i=0;
	   	buff[i++]=ch;
	   	strcpy(new_w.value,buff);
	   	new_w.type=50;//界符 
	   	ch=getc(fin);
	   	flag=1;	
	   	//**************************
	   	//cout<<new_w.value;
	   	return 0;
	}
	else
	{
	   	new_w.type=00;//错误的单词类型 
	   	strcat(new_w.value," ");
	   	//*************************
	   	//cout<<new_w.value;
		return 0;
	}
}

void P()//程序 
{
	getWord();//main
	if(strcmp(new_w.value,"main"))//当new_w.value不等于main满足条件 
	{
		error("缺少main"); 
	}
	getWord();//(
	A();
}
int A() //(){分程序}
{
	if(strcmp(new_w.value,"("))
	{ error("缺少'('");}
		getWord();//)
	if(strcmp(new_w.value,")"))
	{ error("缺少')'");}
		getWord();//{
	if(strcmp(new_w.value,"{"))
	{ error("缺少'{'");}
		getWord();//int
		B();
		//getWord();
	if(strcmp(new_w.value,"} "))
	{ error("缺少'}'");}
	op="go";
	str1="";
	str2="";
	result="";
	makeFour(op,str1,str2,result); 
	cout<<"语法检查完成,共发现"<<e<<"个错误。"<<endl;	
	return 0;
}
void B()//分程序
{
	C();
	
	if(strcmp(new_w.value,";"))
	{ error("缺少';'");}
	getWord();//a=10;中的a
	D();
}
void C()//变量说明部分 
{
	if(strcmp(new_w.value,"int"))
	{ error("缺少'int'");}
		getWord();//a
		ys[++y_num]=new_w.value;
		F();
}
int F()//标识符表 
{
	if(new_w.type==10)
	{
		getWord();
	}
	F1();//标识符表,标识符 
	return 0;
}
int F1()//标识符 
{
	if(strcmp(new_w.value,";")==0)
	{
		return 0;
	}
	if(strcmp(new_w.value,","))
	{error("标识符错误");}
		getWord();//b
		ys[++y_num]=new_w.value;
	if(new_w.type!=10)
	{error("标识符错误");}
		getWord();
		F1();
	return 0;
} 
//***********************************
void D()//语句部分 
{
	H();//语句 
	D1();//子语句部分
}
int D1()//子语句部分
{	
	if(strcmp(new_w.value,"}")==0)
	{
		getWord();
		if(strcmp(new_w.value,";")==0)
		{
			return 0;
		}
		else{
			H();
	 		D1();
			return 0;
		}	
	}
	if(strcmp(new_w.value,";")==0)
	{
	 	getWord();
	 	H();
	 	D1();
	}//else error("语句错误"); 
	 return 0;
}
int H()//语句 
{/*
	for(int i=0;i<100;i++)
	{
		strcpy(b[i].bds,"???");
	}
	int b_num=0;*/
	if(new_w.type==10)//如果当前符号为标识符,则为赋值语句 
	{	
		f=0; //运算符的个数 		
		flag2=0;
		
		ise(new_w.value);//判断标识符是否定义 
		result=new_w.value;
		//strcpy(b[b_num++].bds,new_w.value);//吧等号左边的值存入数组 
		getWord();
		op=new_w.value;//op="="
	//	strcpy(b[b_num++].bds,new_w.value);
		a[a_num++]=new_w.value;//=号 
		I();//赋值语句
		makeFour(op,str1,str2,result);
		return 0; 
	}
	 else if(strcmp(new_w.value,"if")==0)//判断是否为条件语句 
	 {
	 	flag2=0;
	 	getWord();
		J();//条件语句 
		return 0; 
	 }
	 else if(strcmp(new_w.value,"while")==0)//判断为循环语句 
	 {
		aaa=f_num;
	 	flag2=1;
	 	getWord();
		K();//循环语句
		op="go";
		str1="";
		str2="";
		stringstream ss;
    	ss<<aaa;
    	ss>>result;
    	makeFour(op,str1,str2,result);
    	//修改while跳转到的序号 
    	stringstream ws;
    	ws<<f_num;
    	ws>>four[tj_x].res;
		return 0; 
	 }
	 else if(strcmp(new_w.value,";")==0)
	 {
		return 0;
	 }
	 return 0;
}
int I()//赋值语句
{
	if(strcmp(new_w.value,"="))
	{error("缺乏'='");}
	getWord();
	str1=new_w.value;//str1=a  a+b*a中的a 
	//strcpy(b[b_num++].bds,new_w.value); 
	Q();//表达式
	return 0;
}
int Q()//表达式
{
	X();//项
	Q1();//子表达式 
	return 0;
} 
int X()//项 
{
	Y();//因子 
	X1();//子项 
	return 0;
}
int X1()//子项 
{
	flag1=0;
	if(strcmp(new_w.value,";")==0 || new_w.type==43||strcmp(new_w.value,")")==0)//当下一个字符为;或者关系运算符时,表达式结束 
	{
		return 0;
	}
	else if(new_w.type!=41&&new_w.type!=42&&new_w.type!=43&&strcmp(new_w.value,",")!=0 )
	{
		flag1=1;
		error("缺少';'");
		return 0;
	}
	if(new_w.type==41||new_w.type==42)//加法.乘法运算符 
	{
		
		f++;//运算符加一 
		if(f>1)
		{
			str1=str2;
			result="temp"+f;
		}
		op=new_w.value;
	}
	getWord();
	//strcpy(b[b_num++].bds,new_w.value);
	Y();
	return 0;
}
int Q1() //子表达式 
{
	if(strcmp(new_w.value,";")==0 || new_w.type==43||strcmp(new_w.value,")")==0)//当下一个字符为;或者关系运算符时,表达式结束
	{
		return 0;
	} 
	else if(new_w.type!=41&&new_w.type!=42&&new_w.type!=43&&strcmp(new_w.value,",")!=0)
	{
		if(flag1==0){
			error("缺少';'");
		}
		return 0;
	}
	if(new_w.type==41||new_w.type==42)//加法.乘法运算符 
	{
		
		f++;//运算符加一 
		if(f>1)
		{
			str1=str2;
			result="temp";
		}
		op=new_w.value;
	}
	getWord();
	//strcpy(b[b_num++].bds,new_w.value);
	X();
	return 0;
}
int Y()//因子 
{
	if(new_w.type!=10 && new_w.type!=20 && strcmp(new_w.value,"("))
	{
		error("表达式错误!!!!");
		return 0;
	}
	if(new_w.type==10||new_w.type== 20)//标识符和数字 
	{	
		if(op.compare("+")==0 || op.compare("-")==0 || op.compare("*")==0 || op.compare("/")==0)
		{
			str2=new_w.value;
			if(result=="temp")
			{
				makeFour(op,str1,str2,result);
				str2="temp";
				result="b";
				str1="a";//***************
				op="+";//*********************
			}
		}
		if(new_w.type==10)
		{
			ise(new_w.value);
		}
		getWord();//a-1 zhong de - 
	//	strcpy(b[b_num++].bds,new_w.value);
		a[a_num++]=new_w.value;

		return 0;
	}
	else if(strcmp(new_w.value,"(")==0)
	{
		getWord();
		Q();
		if(strcmp(new_w.value,")")==0)
		{
			return 0;
		}
	}
	return 0;
}
int J()//条件语句 
{
	if(strcmp(new_w.value,"("))
	{
		error("缺少'('");
	 }
	 getWord();
	 str1=new_w.value; 
	 TJ();//条件
	 makeFour(op,str1,str2,result);
	 if(strcmp(new_w.value,")"))
	 {
	 	error("缺少')'");
	 }
	 //使四元式为空 
	  op="";
	  str1="";
	  str2="";
	  result="";
	  getWord();
	  H1();//语句一 
	  if(strcmp(new_w.value,";")==0)
	  {
	   		getWord();
	  }
	  stringstream if_s;//
      if_s<<f_num+1;//   int转string 
      if_s>>four[tj_x].res;//
      
      tj_x=f_num;
      op="go";
      str1="";
	  str2="";
	  result="";
	  makeFour(op,str1,str2,result);//满足if条件之后 ,跳过else语句 
	  
	  if(strcmp(new_w.value,"else"))
	  {
	  	error("缺少'else'"); 
	  	H1();//语句一
	  }
	  else
	  {
	  	getWord();
	  	H1();//语句一
	  } 
	  stringstream else_s;//
      else_s<<f_num;//   int转string 
      else_s>>four[tj_x].res;//
	return 0; 
}
void K()//循环语句
{
	if(strcmp(new_w.value,"("))
	{
		error("缺少'('");
	}
	getWord();//(a>0)中的a 
	str1=new_w.value;
	TJ();//条件 
	makeFour(op,str1,str2,result);
	if(strcmp(new_w.value,")"))
	{
		error("缺少')'");
	}
	getWord();
	
	if(strcmp(new_w.value,"do"))
	{
		error("缺少'do'");
		H1();//语句1 
	}
	else
	{
		getWord();
		H1();//语句1

	}	
}
int H1()//语句1 
{
	if(strcmp(new_w.value,"{")==0) 
	{
		getWord();
		
		D();//语句部分
		return 0; 
	}
	else
	{
		H();//语句 
		return 0;
	}
}
int TJ()//条件
{
	//进Q之前时(a>0)中的a 
	Q();
	if(strcmp(new_w.value,">")==0)
	op="<=";
	if(strcmp(new_w.value,"<")==0)
	op=">=";
	if(strcmp(new_w.value,">=")==0)
	op="<";
	if(strcmp(new_w.value,"<=")==0)
	op=">";
	if(strcmp(new_w.value,"==")==0)
	op="!=";
	if(strcmp(new_w.value,"!=")==0)
	op="==";
	if(new_w.type!=43)
	{
		error("缺少关系运算符"); 
	}
	getWord();
	str2=new_w.value;
	tj_x=f_num;//记录条件的四元式符号,方便修改他的res 
	Q();
	return 0;
} 
int main()
{
	char Infile[100];
	
	//对文件的读出和写入借用了网上的知识 
	printf("要测试的小程序的名字(.txt):");
    scanf("%s", Infile);
    if ((fin = fopen(Infile, "r")) == NULL)
    {
        printf("\n 读入文件错误 \n");
        return (1);
    } 
   
	P();
	if(e==0)
	{
		printFour();
	}
	else
	{
		cout<<"\n存在语法错误,无法生成四元式"<<endl;
	}
	
	return 0;
}


递归下降分析法 一、实验目的: 根据某一文法编制调试递归下降分析程序,以便对任意输入的符号串进行分析。本次实验的目的主要是加深对递归下降分析法的理解。 二、实验说明 1、递归下降分析法的功能 词法分析器的功能是利用函数之间的递归调用模拟语法树自上而下的构造过程。 2、递归下降分析法的前提 改造文法:消除二义性、消除左递归、提取左因子,判断是否为LL(1)文法, 3、递归下降分析法实验设计思想及算法 为G的每个非终结符号U构造一个递归过程,不妨命名为U。 U的产生式的右边指出这个过程的代码结构: (1)若是终结符号,则和向前看符号对照, 若匹配则向前进一个符号;否则出错。 (2)若是非终结符号,则调用与此非终结符对应的过程。当A的右部有多个产生式时,可用选择结构实现。 三、实验要求 (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 (三)程序要求: 程序输入/输出示例: 对下列文法,用递归下降分析法对任意输入的符号串进行分析: (1)E->eBaA (2)A->a|bAcB (3)B->dEd|aC (4)C->e|dc 输出的格式如下: (1)递归下降分析程序,编制人:姓名,学号,班级 (2)输入一以#结束的符号串:在此位置输入符号串例如:eadeaa# (3)输出结果:eadeaa#为合法符号串 注意: 1.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 2.对学有余力的同学,可以详细的输出推导的过程,即详细列出每一步使用的产生式。 (四)程序思路 0.定义部分:定义常量、变量、数据结构。 1.初始化:从文件将输入符号串输入到字符缓冲区中。 2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。
### 回答1: 递归程序法是一种用于表达式语法分析的方法。它通过递归调用子程序来分析表达式的语法结构。具体来说,它将表达式分解为若干个子表达式,然后递归地对每个子表达式进行分析,最终得到整个表达式的语法结构。 在递归程序法中,通常会使用一个语法分析器来实现。该分析器会根据语法规则对表达式进行分析,并生成相应的语法树。语法树是一种用于表示表达式语法结构的树形结构,其中每个节点表示一个操作符或操作数,而每个子树表示一个子表达式。 递归程序法的优点是简单易懂,易于实现。但是,它也存在一些缺点,比如容易出现递归深度过大的问题,导致程序崩溃。因此,在实际应用中,需要对递归深度进行限制,或者采用其他更高效的语法分析方法。 ### 回答2: 在计算机程序设计中,语法分析是指将输入的表达式或语句分析成一个语法树的过程。这个过程一般分为两个部分,分别是词法分析和语法分析。而本文所要讨论的内容就是语法分析中的递归程序法。 递归程序法是语法分析中最常用的方法之一。它的基本思想是将语法规则分解成若干个子规则,然后递归调用各个子程序,最终解析出整个表达式或语句的语法结构。 具体来说,递归程序法的实现可以分为两个部分: 1. 分析器的构建 首先需要构建一个可以对输入的字符串进行分析的分析器。这个分析器一般包括输入缓冲区、词法分析器和语法分析器。其中输入缓冲区用于存储输入的字符串,词法分析器用于将输入的字符串分解成单词,语法分析器用于对单词序列进行语法分析。 2. 表达式的解析 接下来就是对输入的表达式进行解析的过程。具体步骤如下: (1)根据输入的表达式的语法规则,构建一个语法分析树。 (2)从根节点开始,递归调用各个子程序,对表达式进行解析。 (3)在解析表达式的过程中,如果发现某个子表达式不符合语法规则,则需要返回到上一级节点进行回溯。 (4)最后得到一个完整的语法分析树,结束解析过程。 递归程序法是一种非常常用的语法分析方法,可以处理较为复杂的语法规则,能够适用于大多数编程语言和表达式的解析。同时,在实现上也比较简单易懂,便于多人协作开发和维护。 ### 回答3: d - 表达式语法分析——递归程序法是一种基于递归的编译器设计方法,用于将输入的算术表达式转化为能被计算机执行的代码的过程。 递归程序法的基本思想是将表达式分解成一个个更小的表达式,直到所有的子表达式都成为原子表达式,也就是不可再分的最小单元。在这个过程中,每个子表达式都可以用相应的递归程序来处理,将其转化为计算机可执行的代码。最后,将所有的代码拼接在一起,就可以得到整个算术表达式的可执行代码。 在递归程序法中,通常将算术表达式转化为一个语法树,其中每个节点代表一个子表达式。对于每个节点,都可以对其子节点进行递归处理,直到所有节点都成为叶子节点。 具体来说,递归程序法需要进行以下几个步骤: 1. 词法分析:将算术表达式转化为一系列单词或记号。 2. 语法分析:根据单词或记号建立语法分析树。 3. 代码生成:针对每个节点,根据其语法构造对应的计算机可执行代码。 4. 优化:对生成的代码进行优化,以提高代码执行效率及降低资源占用。 在实际编译器设计中,递归程序法经常被用来处理表达式语法,其具有代码简洁、易于理解等优点。然而,由于递归的深度可能非常大,递归过程中可能出现栈溢出等问题,需合理控制递归深度。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值