标记语言的简单解释器算法C++实现
- 格式:doc
- 大小:109.50 KB
- 文档页数:8
计算机软件技术基础作业二标记语言的简单解释器算法实现1、源程序见包内,经检测可以在MS VC++ 6.0中正确运行。
本次作业,还添加了现场输入测试功能,显得功能更加强大了。
2、标记语言的简单解释器算法实现,在本题中是通过构造树和堆栈实现的。
3、算法思路:读取压入的字符串,如果读到一个新的<>组合,则把它添加到子列中,如果读到了</>组合,则与原有数据进行匹配,如果读到标记的值就把数据直接放到树中去,其他情况就跳出循环直接输出树的内容。
本题考虑到可以换行输入,所以计算了’<’和’/’的数目,如果’<’刚好是’/’就表明XML语言就要结束了!4、数据结构说明本程序使用了数和指针的结构,期间多次使用到了数组。
5、程序流程说明6程序运行的验证过程(1)导入文件(2)直接输入代码(3)括号不匹配情况(4)其它选项7、效果分析本程序不但可以读取文件,而且可以直接从屏幕输入XML语言,方便易行,并且能够进行基本的括号匹配检查,可以作为简单的标记语言解释器进行使用。
8、原创内容及体会刚开始编写这个程序时我真的是了无头绪,后来想到可以用一个字符串数组传递所需要的字符串内容,并且筛选掉不必要的空格符和换行符,于是思路就豁然开朗了,我的编写过程是首先屏幕直接输入输出进行检验,这一步做好之后,我离成功就不远了,接下来就是导入文件的问题了,通过文件指针和fgetc()函数,我很快地解决了这个问题,反思整个编写过程,我发现最让我耗时的地方还是数组和字符串之间的赋值问题,原来数组使用了gets(数组名)就能够很方便地转化为字符串了!另外由于首尾标记名称和标记值可以分行写,这就要考虑什么时候停止读入字符的问题了。
通过仔细观察,我发现当符号‘<’的数量刚好是符号’/’的两倍时,一按下回车键就是停止读入数据之时,就这样我把该解决的问题一个一个地解决掉了!以下是我的最终成果,“软件2.cpp”:#include <iostream>#include <string>#include <vector>#include <stack>using namespace std;class Tree //创建一个树的类{public:Tree(string name){n=name;val="";no=++amount;}string Name(){return n;}void SetV al(string value){val=value;} //设置元素内容void AddChild(Tree *p){child.push_back(p);} //添加子树名称void Print() //输出第n个元素的有关内容{int i;cout<<"Element "<<no<<" - "<<n<<" : ";if(val.size()==0) cout<<"null";else cout<<val;cout<<", child: ";if(child.size()==0) cout<<"null"<<endl;else{for(i=0;i<child.size();++i)cout<<"Element "<<child[i]->no<<" ";cout<<endl;for(i=0;i<child.size();++i)child[i]->Print();}}static int amount; //用来统计元素个数的静态变量private:string n; //树中记录元素名字string val; //树中记录元素内容int no; //树中统计元素个数vector<Tree*> child; //树中用于记录子树};int Tree::amount=0; //tree域内的amount赋值为0char buf[80]; //创建一个buf数组int GetHead(char *xml) //获取标记头,从'<' 开始取遇到'>' 为止字符串{return (sscanf(xml,"<%[^>]>",buf)==1);}int GetV al(char *xml) //获取数据,取遇到'<' 为止字符串{return (sscanf(xml,"%[^<]",buf)==1);}int GetTail(char *xml) //获取标记尾,从'<' 开始取遇到'>' 为止字符串{return (sscanf(xml,"</%[^>]>",buf)==1);}void cut(char *xml,int len){if(strlen(xml)>len)sprintf(xml,"%s",xml+len);elsestrcpy(xml,"");}int main(){char start[800] ,n ,lujing[100]; int i=0,kuo=0,kuo2=0,gang=0,k=0; FILE *fp;cout<<"导入XML文件请按'1' ,即时输入XML标记语言请按'2' ,退出请按其他键:"<<endl;cin>>n; getchar();cout<<endl;if(n=='1'){cout<<"请输入文件路径:"<<endl;gets(lujing);cout<<endl;//if((fp=fopen("test.xml","r"))==NULL) //此行决定所导入文件的来源(如:d:\\test.xml)!没有路径则表示出处在源程序所在文件夹中。
if((fp=fopen(lujing,"r"))==NULL){cout<<"File open error!"<<endl;exit(0);}cout<<"您导入的文件内容是:"<<endl;while(!feof(fp)){start[-1]='\0';start[i]=fgetc(fp); //先使用一个数组start[800]存储数据,判别程序是否结束cout<<start[i];if(start[i]=='<')kuo++;else if(start[i]=='>')kuo2++;else if(start[i]=='/')gang++;else;if(kuo==gang*2 && start[i]=='>')break;else if(kuo!=2*gang&&start[i]=='\n');else if(start[i]==' ');elsei++;if(kuo2<kuo-1||kuo2>kuo){cout<<"括号不匹配!"<<endl;//cout<<"2"<<endl;exit(0);}//start[i]=fgetc(fp);//cout<<start[i];//i++;}if(start[i]!='>'){cout<<endl<<endl<<"此文件括号不匹配!"<<endl;//cout<<"2"<<endl;exit(0);}cout<<endl;if(fclose(fp)){cout<<"Can not close the file!"<<endl;exit(0);}}else if(n=='2') //在这种模式下,可以通过屏幕输出XML语言!{cout<<"请输入XML语言,首尾标记名称和标记符可以分行写, 注意括号要匹配:"<<endl;start[-1]='\0';while(k!=1){start[i]=getchar(); //先使用一个数组start[800]存储数据,判别程序是否结束if(start[i]=='<')kuo++;else if(start[i]=='>')kuo2++;else if(start[i]=='/')gang++;else;if(kuo==gang*2 && start[i-1]=='>' &&start[i]=='\n'){k=1; i++;}else if(kuo==gang*2 && start[i-1]!='>' &&start[i]=='\n'){cout<<"括号不匹配!"<<endl;//cout<<"1"<<endl;exit(0);}else if(kuo!=2*gang&&start[i]=='\n');else if(start[i]==' ');elsei++;if(kuo2<kuo-1||kuo2>kuo){cout<<"括号不匹配!"<<endl;//cout<<"2"<<endl;exit(0);}}}else //按其他键则退出!{cout<<"您选择了退出,欢迎您下次的使用!!!"<<endl;exit(0);}char xml[800];strcpy(xml,start);//gets(xml);//strcpy(xml,"<class><student><name>ABC</name><id>123456</id>group1</student></class>");//puts(xml);cout<<endl<<"以下是解释语言:"<<endl;Tree *root=NULL,*p,*q;stack<Tree*> S; //定义堆栈while(1){if(GetTail(xml)) //到达树根{if(S.empty()){cerr<<"expect <tag>"<<endl;break;}if(S.top()->Name()==string(buf)){S.pop();if(!S.empty()) p=S.top();else break;}else{cerr<<"not match"<<endl;break;}cut(xml,strlen(buf)+3);}else if(GetHead(xml))//到达树头{q=new Tree(string(buf));if(root==NULL){p=root=q;}else{p->AddChild(q);p=q;}S.push(q);cut(xml,strlen(buf)+2);}else if(GetV al(xml))//到达内容部分{p->SetV al(string(buf));cut(xml,strlen(buf)); //运用自己定义的cut函数}else break; //跳出循环}if(root) root->Print(); //如果树指针root不是结束,则输出root的内容return 0;}程序和上次的一样都显得很长,但这也正是大程序的特点之所在了吧,O(∩_∩)O哈哈~。