LL(1)改进

源代码链接:https://download.csdn.net/my

1.目录结构

2.文件内容

 文件1:

文件2:

文件3:

文件4:

文件5:

3.源代码部分

1.建立存储模型

public class staticData {
	//非终结符
	public static String nfinalSign=null;
    //终结符
    public static String finalSign=null;
    //产生式表
    public static String[][] productType;
    //first集表
    public static String[] firstSet;
    //first集元素对应的产生式
    public static String[][] firstProductType;
    //follow集表
    public static String[] followSet;
}

.

2.文件扫描

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/*
 * 1.提取终结符与非终结符
 * 2.构建非终结产生式列表
 */
public class TakeSign {
	public  void selectFile(int number) throws IOException {
    	Scanner scan=new Scanner(System.in);
       /*
        * 文件读取部分
        */
    	String AppCodeUrl=System.getProperty("user.dir")+"/src/grammerRules";
		//建立文件对象
    	File file=new File(AppCodeUrl,"grammerRules"+number);
    	//建立你问价读取对象
    	FileReader fileReader=new FileReader(file);
    	BufferedReader bufferedReader=new BufferedReader(fileReader);
    	//存储产生式String----代表若干个产生式
        List<String> signStrList=new ArrayList<String>();
        //文件读取
        String tempstr=null;
        while((tempstr=bufferedReader.readLine())!=null) {
        	signStrList.add(tempstr);
        }
        bufferedReader.close();
    	//输出
        System.out.println("读取相关文法如下:");
        for (String string : signStrList) {
			System.out.println(string);
		}
    	/*
    	 * 提取终结符与非终结符
    	 */
        //非终结符的相关产生式
        staticData.productType=new String[signStrList.size()][7];
    	//非终结符号提取
        for (int i = 0; i < signStrList.size(); i++) {
        	staticData.nfinalSign+=""+signStrList.get(i).charAt(0);
			//提取产生式存放到后续
			String temp=signStrList.get(i);
			int index=temp.indexOf('>');
			temp=temp.substring(index+1,temp.length());
			String[] E_f=temp.split("\\|");
			int num=0;
			for (String it : E_f) {
				staticData.productType[i][num++]=it;
			}
		}
        System.out.println(signStrList.size()+"   "+staticData.nfinalSign.length());
        //终结符提取
        staticData.finalSign="";
    	for (String it:signStrList) {
			for (int i = 0; i < it.length(); i++) {
				//临时符号
				char tempchar=it.charAt(i);
				//----判断终结符
				if(tempchar!='>'&&tempchar!='-'&&tempchar!='n'&&tempchar!='@'&&tempchar!='|'&&(tempchar<'A'||tempchar>'Z')) {
					if(staticData.finalSign==null||FinalExist(tempchar)) {
						staticData.finalSign+=""+tempchar;
					}
				}
			}
		}
//------------------------------对是否为左递归文法进行判断---------------//
    	for (int i = 0; i <staticData.nfinalSign.length(); i++) {              //对每一个非终结符进行考察
			  juageLeft(i,i);
        }
//--------------------------------控制台输出----------------------------//
    	/*
    	 * 输出终结符
    	 */
    	System.out.println("\n\n>>>终结符如下:");
    	for (int i = 0; i < staticData.finalSign.length(); i++) {
			System.out.print(staticData.finalSign.charAt(i)+"  ");
		}
    	System.out.println();
    	/*
    	 * 输出非终结符
    	 */
    	System.out.println("\n\n>>>非终结符及其相关候选产生式如下:");
    	for (int i = 0; i < signStrList.size(); i++) {
    		System.out.println(staticData.nfinalSign.charAt(i)+"候选产生式:");
			for (String it :staticData.productType[i]) {
				if(it==null)
					break;
			    else {
			    	System.out.println(it+" ");
			    }
			}
		}
	}
//-------------------------子函数区域-----------------------------------//    
    /*
     * 判断终结符是否已经加入过
     */
    public  Boolean FinalExist(char tempchar) {
    	if(staticData.finalSign.contains(""+tempchar)) {
    		return false;
    	}
		return true;
    }
    /*
     * 
     * 
     *          判断是否含有左递归
     * i--------代表判断当前是那个文法
     * recursive---递归的非终结符
     */
    public  void juageLeft(int i,int recursive) {
    	for (int j = 0; j < staticData.productType[recursive].length; j++) {         //遍历所有产生式
			for(int k=0;staticData.productType[recursive][j]!=null&&k<staticData.productType[recursive][j].length();k++) {       //对每一个产生式考察
				String temp=staticData.productType[recursive][j];
				try {
					if(staticData.nfinalSign.charAt(i)==temp.charAt(0)) {
						//判断首符号是否与当前考察的非终结符是否相等
						System.out.println("本文法含有左递归,不属于LL(1)文法!!!--------->("+temp.charAt(0)+"->"+temp+"...)");
						System.exit(0);
						//throw new Exception("此文发还有左递归,不属于LL(1)文法!!!");
					}else if(staticData.nfinalSign.contains(""+temp.charAt(0))){        //判断是否为终结符这是否需要进行递归操作
						//求其对应位置
						int place=staticData.nfinalSign.indexOf(temp.charAt(0));
						//递归进行
						juageLeft(i,place);
					}					
				} catch (Exception e) {
					System.out.println(e);
				}finally {
				}
		}
	  }
   }
}

 3.提取first集

/*
 * 构建first集
 */
public class FirstSet {
	   static int num=0;
	   //非终结符
   	   private String nFinalSign;;
	   //终结符
	   private String finalSign;
   	   //first集
       private String[] firstSet;
       //产生式表                                                                                                                                                                                               
       String[][] NfinalP_table=new String[nFinalSign.length()][finalSign.length()];
       //首符集对应生式的表
       String[][] firstSetp=new String[nFinalSign.length()][finalSign.length()];
       
       
       
       /*
        * 构造方法
        */
   	public FirstSet(String nFinalSign, String finalSign, String[][] nfinalP_table) {
		super();
		this.nFinalSign = nFinalSign;
		this.finalSign = finalSign;
		NfinalP_table = nfinalP_table;
	}
    
   /*
    * 求解first集
    */
	public  String[] firstConstruction() {
    	//将first置空
    	firstSet=new String[nFinalSign.length()];
    	//初始化
    	for (int i = 0; i < firstSet.length; i++) {
			firstSet[i]="";
		}
    	//first表
    	String[][] foreTable=new String[nFinalSign.length()][finalSign.length()];
    	/*
    	 * 求解first集
    	 */
    	//利用第<<1>><<2>>条规则求取first集及first集中每个对应的产生式
    	System.out.println("first集中元素所对应的产生式");
    	for (int j = 0; j < nFinalSign.length(); j++) {//遍历每一个非终结符
    		num=0;
    		takeProPress(j,nFinalSign.charAt(j),NfinalP_table[j],null);
		}	
    	//利用第<<3>>条规则求取判断是否将@--空添加到first集中
    	for (int i = 0; i < firstSetp.length; i++) {
			if(juagenull(i)) {
				if(!firstSet[i].contains("@")) {
				//向首符集添加@
				firstSet[i]+="@";
				}
			}
		}
    	System.out.println("--------------------");
    	System.out.println("first集如下:");
    	for (int i = 0; i <firstSet.length; i++) {
			System.out.println(nFinalSign.charAt(i)+":"+firstSet[i]);
		}
    	return firstSet; 
	}

	/*
	 * 求解first集元素对应的产生式
	 */
	public String[][] firstToProductTable() {
		return firstSetp;
	}
	
//-------------------------------子程序部分--------------------------------//	
       /*
        * 获取每一个
        */
      //int nplace对应求解的非终结符
      // String Nfinal非终结符
      // 产生式表
      // first集合表
      // Nuchangedstr
    public  void takeProPress(int nplace,char Nfinal,String[] NfinalP_arr,String Nuchangedstr){
    	//遍历每一个候选产生式
    	for (String p : NfinalP_arr) {    		
    		char firstSign=p.charAt(0);   		                                               
			if(firstSign=='@'||jugeFinal(firstSign)){      //1.根据第一条规则进行匹配
				//添加到首符集
				firstSet[nplace]+=firstSign;
				//填写对应的首符集对应产生式
				if(Nuchangedstr==null) {
				firstSetp[nplace][num]=p;
				}
				else {
					firstSetp[nplace][num]=Nuchangedstr;
				}
				System.out.print(num+":  "+firstSetp[nplace][num]);
				if(num==0)
					System.out.println();
				num++;
			}else{                                          //2.根据第二条规则进行匹配
				//获取首符号的位置
				int fsplace=nFinalSign.indexOf(firstSign);
				if(Nuchangedstr==null)
				takeProPress(nplace,firstSign,NfinalP_table[fsplace],p);
				else {
					takeProPress(nplace,firstSign,NfinalP_table[fsplace],Nuchangedstr);
				}
			}
		}	
    }
    /*
     * 判别其中一个非终结符的首符集是否应该添加@空
     */
    public  boolean juagenull(int nplace) {
  next:  	for (int i = 0; i < NfinalP_table[nplace].length; i++) {     //判别每个产生式
    		String temp=NfinalP_table[nplace][i];
    		if(temp.equals("@"))
    			continue;
    		char pAtrr[]=temp.toCharArray();
			for (int j = 0; j < pAtrr.length; j++) {
				if(jugeFinal(pAtrr[j]))                              //是终结符
					continue next;
				else {                                               //是非终结符
					//判断是否含有@
					//获取位置信息
					int mayNullPlace=nFinalSign.indexOf(pAtrr[j]);
					//判断是否其非终结符中含有@
					if(!juageHavenull(mayNullPlace)) {
						continue next;
					}
				}
			}
			return true;
		}
        return false;
    }
    /*
     * 判断是否含有终结符
     */
    public  boolean juageHavenull(int mayNullPlace) {
    	for (String string : NfinalP_table[mayNullPlace]) {
			if(string.equals("@")) {
				return true;
			}
		}
    	return false;
    }
    /*
     * 判断是否为终结符
     */
    public  Boolean jugeFinal(char c) {
    	String temp=""+c;
    	if(finalSign.contains(temp)) {
    		return true;
    	}else {
    	    return false;
    	}
    }
}

4.提取follow集

public class FollowSet {
	//终结符
    static String finalSign="i+*()#";
	//非终结符
	static String nFinalSign="EeTtF";
	//存储每个非终结符的first集
    static String[] firstSet=new String[finalSign.length()];
    //存储每个非终结符的follow集
    static String[] followdSET=new String[finalSign.length()];
    //相关非终结符候选产生式所对应的表
    static String[][] NfinalP_table=new String[nFinalSign.length()][finalSign.length()];
    //首符集对应产生式的表
    static String[][] firstSetp=new String[nFinalSign.length()][finalSign.length()];
    //右递归标志
    //static Boolean rightb=false;//默认无右递归
//    //follow添加状态表
//    static String[][] followState=new String[3][nFinalSign.length()];
	public static void main(String[] args) {
		//first集进行初始化
		firstSet[0]="(i";
		firstSet[1]="+@";
		firstSet[2]="(i";
		firstSet[3]="*@";
		firstSet[4]="(i";
		//产生式表初始化
		NfinalP_table[0]=new String[]{"Te"};	
    	NfinalP_table[1]=new String[]{"+Te","@"};
    	NfinalP_table[2]=new String[]{"Ft"};
    	NfinalP_table[3]=new String[]{"*Ft","@"};
    	NfinalP_table[4]=new String[]{"(E)","i"};
	    /*
	     * follow集初始化
	     */
    	for (int i = 0; i < followdSET.length; i++) {
			followdSET[i]="";
		}
    	/*
    	 * follow集状态表初始化
    	 */
//    	for (int i = 0; i < followState[0].length; i++) {
//			followState[0][i]="0";
//		}
//    	for (int i = 0; i < followState[1].length; i++) {
//			followState[1][i]="";
//		}
//    	for (int i = 0; i < followState[2].length; i++) {
//			followState[2][i]="n";
//		}
		//在所有产生式中搜索每一个非终结符
    	//开始符号添加符号‘#’
    	followdSET[0]="#";                                      //第-----------------------------------1-------------------条规则
		for (int i = 0; i < nFinalSign.length(); i++) {         //获取每一个非终结符
			
			
			/*
			 * 针对表进行遍历
			 */
			for (int j = 0; j < nFinalSign.length(); j++) { //遍历其中一个非终结符的产生式
				for (int j2 = 0; j2 < NfinalP_table[j].length; j2++) {    //在每个产生式中搜索对应的非终结符
					//*********获取产生式*********
					String temp=NfinalP_table[j][j2];
					char[] prochars=temp.toCharArray();
					//在字符串中搜索非终结符
					for (int k = 0; k <prochars.length; k++) {        //当前产生式
						//与非终结符进行比较  prochars[k]当前比较元素
						if(prochars[k]==nFinalSign.charAt(i)) { //---------------------是否与此非终结符相等
							//是否为最后面的元素     
							if(k==prochars.length-1) {         //是最后元素第-----------------------------------3-------------------条规则      
								//判断是否属于右递归
								//进行右推导判断  j--->i 
								for (int k2 = 0; k2 < followdSET[j].length(); k2++) {
									if(!followdSET[i].contains(""+followdSET[j].charAt(k2)))
									followdSET[i]+=followdSET[j].charAt(k2);
								}
//								juageRight(i, j);
//								if(nFinalSign.charAt(i)==nFinalSign.charAt(j)||rightb) {//直接右递归或间接右递归
//									rightb=false;
//									break;
//								}else {                                        //非右递归
//									int place=nFinalSign.indexOf(prochars[k]);
//									//将i的follow集添加到中
//									followState[0][place]="1";
//								    followState[1][place]+=prochars[k];
//								}
							}else {                             //非最后元素第----------------------------------2-------------------条规则
								//获取后面元素
								char back=temp.charAt(k+1);
								
								if(!jugeFinal(back)) {          //非终结符    
									//求取对应first集位置
									int place=nFinalSign.indexOf(back);
									for (int l = 0; l < firstSet[place].length(); l++) {
										if(!followdSET[i].contains(""+firstSet[place].charAt(l))&&firstSet[place].charAt(l)!='@') {
										followdSET[i]+=firstSet[place].charAt(l);
										}
										//-----------第三条特殊规则                              A->**Bn   n->@----------------//
										//截取后续字符串
										String subString=temp.substring(k+1);
										//判断后续字符串是否都能推出@,也就是所有符号first集都含有@
										if(juageStrnull(subString)) {
											for (int k2 = 0; k2 < followdSET[j].length(); k2++) {
												if(!followdSET[i].contains(""+followdSET[j].charAt(k2)))
												followdSET[i]+=followdSET[j].charAt(k2);
											}
											
										}
									}
								}else if(!followdSET[i].contains(""+back)){//终结符
									followdSET[i]=back+followdSET[i];
								}
							}
							break;
						}
						//rightb=false;
					}
				}
			}
		}
//		for (int j = 0; j < followState.length; j++) {
//			for (int j2 = 0; j2 < nFinalSign.length(); j2++) {
//				System.out.println(followState[j][j2]);
//			}
//		}
//-------------------------------------第三条规则的添加-----------------------------//
		
		
		
		
		
//--------------------------------------follow集输出操作----------------------------//
		for (int i = 0; i < nFinalSign.length(); i++) {
			System.out.println(nFinalSign.charAt(i)+":"+followdSET[i]);
		}
	}
//----------------------------子函数部分---------------------------------------------//
	/*
     * 判断是否为终结符
     */
    public static Boolean jugeFinal(char c) {
    	String temp=""+c;
    	if(finalSign.contains(temp)) {
    		return true;
    	}else {
    	    return false;
    	}
    }
    /*
     * 判断后续字符串符号是否都能推出@
     */
     public static Boolean juageStrnull(String string) {
    	 for (int i = 0; i < string.length(); i++) {
			//获取第i个字符
    		 char c=string.charAt(i);
    		 if(jugeFinal(c)) {
    			 return false;
    		 }else {
    			 //获取其首符集位置
    			 int firstLocation=nFinalSign.indexOf(c);
    			 //判断首符集是否含有@
    			 if(!firstSet[firstLocation].contains("@"))
    				 return false;
    		 }
		}
		return true;
     }
    /*
     * 判断非终结符是否为右递归
     * i对应非终结符
     * recursive对应右边的非终结符
     */
//	public static void juageRight(int i,int recursive) {
//		    //recursive对应的非终结符的产生式进行考察
//			for (int j = 0; j <NfinalP_table[recursive].length; j++) {  
//				String prostring=NfinalP_table[recursive][j];
//				//获取最右的元素
//				int index=prostring.length();
//				char rightElement=prostring.charAt(index-1);
//				//判断是否为终结符
//				if(finalSign.contains(""+rightElement)) {                                         //终结符
//					return;
//				}else if(rightElement==nFinalSign.charAt(i)){                                     //非终结符判断是否相等
//				    rightb=true;
//				    return;
//				}else {
//					juageRight(i,rightElement);
//				}
//			}
//	}
}

5.建立预分析表

/*
 * 建立预分析表
 */
public class BuildTable {
      public static void main(String[] args) {
		//非终结符
    	  String nFinalSign="EeTtF";
    	//终结符
    	  String finalSign="i+*()#";
//    	//first表
//    	  char[][] first=new char[nFinalSign.length()][finalSign.length()];
//    	//follow表
//    	  char[][] follow=new char[nFinalSign.length()][finalSign.length()];
    	
    	  //first集
    	  String[] firstset= {"(i","+@","(i","*@","(i"};
    	  //follow集
    	  String[] followset= {")#",")#","+)#","+)#","*+)#"};
    	  //预测分析表
    	  String[][] foreTable=new String[nFinalSign.length()][finalSign.length()];
    	  //firstset对应产生式
    	  String[][] firstSetp=new String[nFinalSign.length()][];
    	  firstSetp[0]=new String[] {"Te","Te"};
    	  firstSetp[1]=new String[] {"+Te"};
    	  firstSetp[2]=new String[] {"Ft","Ft"};
    	  firstSetp[3]=new String[] {"*Ft"};
    	  firstSetp[4]=new String[] {"(E)","i"};
    	//构建分析表
    	for (int i = 0; i < foreTable.length; i++) {
    		for (int j = 0; j < foreTable[i].length; j++) {
				String temp=""+finalSign.charAt(j);
				if(firstset[i].contains(temp)){//若first及中含有
					//字符集的位置
					 int index=firstset[i].indexOf(temp);
				     foreTable[i][j]=firstSetp[i][index];
				}else if(firstset[i].contains(""+"@")&&followset[i].contains(temp)){
					foreTable[i][j]="@";
				}else {
					foreTable[i][j]="n";
				}
			}
		}
    	/*
    	 * 将构建的预测分析表输出
    	 */
    	System.out.println("非终结符:"+nFinalSign);
    	System.out.println("终结符:"+finalSign);
    	for (String[] strings : foreTable) {
			for (String string : strings) {
				System.out.printf("%s\t",string+" ");
			}
			System.out.println();
		}	
    }
}

6.总控程序

import java.util.Scanner;
public class TotalControl {
	    //终结符串
	    static String  final_sign=null;
	    //非终结符串
	    static String  Nfinal=null;
		public static void derive() {
        	 Scanner sc=new Scanner(System.in);
///
/*----------------初始化表---------------------
// ///*/
        	//接受终结符
        	System.out.println("请输入终结符号集合:");
        	final_sign=sc.nextLine();
        	//接受非终结符
        	System.out.println("请输入非终结符号集合:");
            Nfinal=sc.nextLine();
			
        	 //根据终结符与非终结符的长度创建一个表      
        	int h=Nfinal.length();
        	int l=final_sign.length();
        	String[][] Table=new String[h][l];
            //System.out.println(Table.length);
        	//System.out.println(Table[0].length);
        	System.out.println("请输入矩阵句型:");
        	for (int i = 0; i < Table.length; i++) {            //行
				for (int j = 0; j < Table[0].length; j++) {     //列
					Table[i][j]=sc.next();
				}
			}
        	for (String[] strings : Table) {
				for (String string : strings) {
					System.out.printf("%s\t",string);
				}
				System.out.println();
			}
        	//接受输入要扫描的字符串
        	System.out.println("请输入你所要扫描的字符串:");
        	String input_str=sc.next();
        	System.out.println(input_str);
        	sc.close();
        	
/*/
//--------------------如下进行匹配------------------------/
/*/
        	//构建栈
        	char[] sign_stack=new char[10]; 
        	
        	//构建指针
        	int top=1;           //指向栈顶
        	int lr=0;            //指向扫描字符
        	
        	//初始化栈
        	sign_stack[0]='#';
        	sign_stack[1]=Nfinal.charAt(0);
        	
        	//表的行坐标
        	int hang=0;
        	int lie=0;
        	
        	//取得栈顶元素
        	char stack_top;
        	while(sign_stack[top]!='#'||input_str.charAt(lr)!='#') {
        		
        		stack_top=sign_stack[top];      //取出栈顶元素
        		
                /*/
                 * 
                 *            问题存在区域
                 * 
                 */
        		
        		//---------------判断栈顶元素是否为终结符--------------
        		if(!isNfinal(stack_top)) {                                     //是终结符   
        			 //与扫描串当前字符匹配 
        			if(stack_top==input_str.charAt(lr)){                       //可以匹配
        				lr++;     //进行下一个字符匹配
        				System.out.println("lr top:"+lr);
        				sign_stack[top]='0';
        				top--;    //弹出栈顶元素终结符
        				if(sign_stack[top]=='#')
        					break;
        				stack_top=sign_stack[top];
        			}else {                                                    //句型不匹配推出
        				System.out.println("GGGG!!!");
        				break;
        			}
        		}
        		//---------------进行非终结符推导----------------------
        		
        		hang=Nfinal.indexOf(stack_top);                          //查找在表中的行位置
        		lie=final_sign.indexOf(input_str.charAt(lr));            //查找在表中的列位置
        		//将当前表中符号串与字符进行比较
        		if(Table[hang][lie].equals("n")) {                       //1.如果没有匹配的
        			System.out.println("GG!!");
        			break;
        		}else {
        			  if(Table[hang][lie].length()==1&&Table[hang][lie].charAt(0)==input_str.charAt(lr)) {  //如果终结符匹配成功将栈顶元素弹出,并且进行下一个字符匹配
        			     sign_stack[top]='0';                        //出栈
        			     top--;                                      //栈顶指针变化
                         lr++;                                       //扫描指针发生变化
                         System.out.println("lr:"+lr);
        		         }else if(Table[hang][lie].equals("@")){              //如果存在是空@则弹出栈顶元素
        		         
        		         sign_stack[top]='0';
        			     top--;
        		        }else {                                              //否则将栈顶元素出栈并将推导式入栈
        			    for(int i=Table[hang][lie].length()-1;i>=0;i--) {
        			    	//判断将要插入的字符是否为非终结符
        			    	
        			        sign_stack[top]=Table[hang][lie].charAt(i);       
        			        top++;
        			    }
        			    top--;
        		    }
        	  }
         }
/*//
 *                  判断匹配成功
 *//
        	if(sign_stack[top]=='#'&&input_str.charAt(lr)=='#')
        	  System.out.println("匹配成功!!!"+lr);
        	else {
        		System.out.println("出错位置:"+(lr+1));
        	}
        	
        	
       }
/*//
 *                 判断字符是否为非终结符
 *//
		private static boolean isNfinal(char temp) {
			for (int i = 0; i < Nfinal.length(); i++) {
				if(temp==Nfinal.charAt(i)) return true;
			}
			return false;
		}
}

7.主函数

import java.io.IOException;
import java.util.Scanner;

public class Mian {

//--------------------------------定义部分--------------------------//	
	   //非终结符存储
	   private static String NFinalSign="";
	   //终结符号
	   private static String FinalSign;
	   //非终结符的相关产生式
	   private static String[][] NFinalTable;
	   
	   
	   
//----------------------------------主函数部分-----------------------//	   
    public static void main(String[] args) throws IOException {
    	Scanner scan=new Scanner(System.in);
        /*
         * 文件读取部分
         */
     	//获取用用程序程序路径
     	String AppCodeUrl=System.getProperty("user.dir")+"/src/grammerRules";
     	//进行文件选择
     	System.out.println("文件标号:1");
     	System.out.println("文件标号:2");
     	System.out.println("文件标号:3");
     	System.out.println("文件标号:4");
     	System.out.println("文件标号:5");
     	System.out.println("请选择:");
     	int selectFileCode=scan.nextInt();
        //文件扫描部分
     	TakeSign takeSign=new TakeSign();
     	takeSign.selectFile(selectFileCode);
     	//first集提取部分、
     	FirstSet firstSet=new FirstSet(NFinalSign,FinalSign,NFinalTable);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值