2020面向对象程序设计寒假作业3 题解
作业描述 | 详情 |
---|---|
这个作业属于哪个课程 | 班级链接 |
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | 编程题: 继续完成作业二的编程题。 1. 优化架构,思考代码的拓展性,比如我需要增加其他功能,如选择,循环语句怎么办。 2. 思考:可以参考现有的编程语言,把这些语言的内容加入。如选择、循环语句、函数、或者扩大数字范围,支持负数等。 |
作业正文 | 2020面向对象程序设计寒假作业3 题解 |
其他参考文献 | C++之vector类型的使用和迭代器使用 |
参考 本人第二次作业 后,重新规划了架构
题目要求
- 继续完成作业二的编程题。
- 优化架构,思考代码的拓展性,比如我需要增加其他功能,如选择,循环语句怎么办。
- 思考:可以参考现有的编程语言,把这些语言的内容加入。如选择、循环语句、函数、或者扩大数字范围,支持负数等。
优化目标
- 在一定程度上减少码量
- 增加一定的封装,使得代码可读性提高
- 增加对负数的处理
- 尽可能使用引用来实现传值,方便后续的拓展
- 增加对其它运算的支持
思考过程
- 在实现作业二的过程中,发现 World 类中,出现了较多的错误抛出方法,因此构建一个新的类 ErrorRepository 来专门实现错误抛出
- 在实现作业二的过程中,发现赋值语句的右侧,可以是变量或者数字。最后如果是返回数值,则一定是这两者的值之一。对于在代码中多次出现:试探是否是数值、再试探是否是变量,这一重复操作。故此,将两个类用一个新的类 ValueRepository 进行封装。在该类中实现方法,进行查询
- 通过查询 相关资料 ,学习到可以使用迭代器实现变量的操作
- 拓展数域至负数,实际上就是考虑“负”以及对负号的处理
- 在实现作业二的过程中发现,大部分代码量花费在对语句的划分上,直接构造一个新的方法来实现对语句的划分
因此开始构建:
一、变量库(VariableRepository)
将方法 VariableFind 改为 bool 类型返回值,返回值表示是否查得到(即查得到为 true ,查不到为 false)。而本身返回变量在 vector 中索引的操作,改为用引用储存变量的迭代器
bool VariableFind(vector<int>::iterator &v,string name){//v 为 vector<int> 型的迭代器的一个引用
if(variableMap.find(name)==variableMap.end()) return false;//找不到
v=variableValue.begin()+variableMap[name];
return true;
}
而因此,增删改查操作都可以更加简便的实现,下面以增加为例:
bool VariableAdd(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v+=value;
return true;
}
返回值代表是否修改成功,而是否成功的决定因素即为变量是否存在
而还可进而实现变量的删除操作:
bool VariableDelete(string name){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;//变量不存在,下同
variableValue.erase(v);
variableMap.erase( variableMap.find(name) );
return true;
}
且在作业二的实现过程中,发现语句:整数 <变量名>
与语句 整数 <变量名> 等于 <数值>
具有一定的区别,因此,为避免在 World 中占据方法,因此封装回 VariableRepository 类中:
bool VariableApplyAssign(string name,int value){
if( !VariableApply(name) ) return false;
VariableAssign(name,value);
return true;
}
而考虑到一般的 C++ 变量都需要支持的五则运算包括:增加、减少、乘以、除以和取模,而对于 C++ 的取模与取余运算有有一定的区别。故增添取余运算,区别于取模
对于位运算,暂且先不进行考虑,因为涉及到对数位的处理;以及目前数字的输入输出环境仅支持 -99~99 ,加入位运算有一些大材小用的感觉
增加操作在上文已经可见,减少、乘以、除以、取模操作相差不大,以乘以为例,直接给出代码:
bool VariableMultiply(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v*=value;
return true;
}
取余运算对于取模运算最大的区别,在于取余后为正数,也可通过取模等操作实现:
bool VariableRemainder(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v=(*v%value+value)%value;
return true;
}
下面给出完整代码:
VariableRepository.h
#include<vector>
#include<string>
#include<map>
using namespace std;
#ifndef VARIABLEREPOSITORY
#define VARIABLEREPOSITORY
class VariableRepository{
private:
vector<int> variableValue;
map<string,int> variableMap;
bool VariableFind(vector<int>::iterator &v,string name){//v 为 vector<int> 型的迭代器的一个引用
if(variableMap.find(name)==variableMap.end()) return false;//找不到
v=variableValue.begin()+variableMap[name];
return true;
}
public:
VariableRepository() {}
~VariableRepository() {}
bool VariableApply(string name){
vector<int>::iterator v;
if( VariableFind(v,name) ) return false;//变量存在
variableMap[name]=variableValue.size();//存地址
variableValue.push_back(0);//赋初始值为 0
return true;
}
bool VariableDelete(string name){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;//变量不存在,下同
variableValue.erase(v);
variableMap.erase( variableMap.find(name) );
return true;
}
bool VariableAssign(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v=value;
return true;
}
bool VariableApplyAssign(string name,int value){
if( !VariableApply(name) ) return false;
VariableAssign(name,value);
return true;
}
bool VariableAdd(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v+=value;
return true;
}
bool VariableSubtract(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v-=value;
return true;
}
bool VariableMultiply(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v*=value;
return true;
}
bool VariableDivide(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v/=value;
return true;
}
bool VariableModule(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v%=value;
return true;
}
bool VariableRemainder(string name,int value){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
*v=(*v%value+value)%value;
return true;
}
bool VariableShow(int &value,string name){
vector<int>::iterator v;
if( !VariableFind(v,name) ) return false;
value=*v;
return true;
}
};
#endif
二、数字库(NumberRepository)
同变量库(VariableRepository)一样,将原本方法的返回值全部设置为 bool 型,而原本的返回值用引用实现
同时,加入了负数。对于负数,使用特判“负”或负号的方法实现:
bool ToChar(string &cn,int value){
if(value<-99||value>99) return false;
cn="";
if(value<0) cn="负",value=-value;//先判定是否是负数
if(value<=10) cn+=numberChar[value];
else if(value<20) cn+=numberChar[10]+numberChar[value-10];//十几的形式
else if(value%10==0) cn+=numberChar[value/10]+numberChar[10];//几十的形式
else cn+=numberChar[value/10]+numberChar[10]+numberChar[value%10];
return true;
}
bool ToNumber(int &value,string name){
bool negative=0;
if(name.substr(0,2)=="负") negative=1,name=name.substr(2);//先判定是否是负数
if( !FormatChar(name) ) return false;//失败
int ten,base;
FindChar( ten,name.substr(0,2) );
FindChar( base,name.substr(2,2) );
value=ten*10+base;
if(negative) value=-value;
return true;
}
其次,本人在此基础上,优化了输出的范围:为所有 int 范围内
根据本人翻阅小学数学书,大数的读法与写法,其中介绍了大数的读法:
- 根据中国的读法,四个数位为一级
- 从小到大,数级为:个、万、亿等(其余不在 int 范围内)
- 读数时从大的数级往小读
- 若存在更大数级的情况下,本数级若不满四位,且前一数级不全为 0 的话,应加前缀零。如:20147,读作:两万零一百四十七
- 最高位数级若介于 11 至 19 ,应读作“十*”的形式
- 凡是非最高位数级, 11 至 19 均应读作“一十*”的形式
- 数级内,若后缀全为零的不再补充后缀。如:2100300,读作:二百一十万零三百
- 数级内,两非零数位间存在零,读且仅读一个零。如:1003,读作:一千零三
依次,构造出新的 ToChar 方法
首先,对于输入的数特判是否会超出 int 范围(虽然现在的代码中,变量使用 int 储存值,但之后会改成 longlong 甚至高精)
对于在 int 范围内的数,分别提取亿级、万级、个级,依次用 ToCharInThousand 方法处理数级内读法
最后根据前缀情况(前缀是否存在、前缀是否含零),判定是否要前补零
给出这两个方法的代码:
void ToCharInThousand(string &cn,int value){
if(value<20){
if(value<=10) cn+=numberChar[value];
else cn+=numberChar[10]+numberChar[value-10];
return ;
}
bool prefix=0;
if(value>=1000) cn+=numberChar[value/1000]+numberChar[1000],prefix=1;
else if(prefix&&value%1000!=0) cn+=numberChar[0],prefix=0;
value%=1000;
if(value>=100) cn+=numberChar[value/100]+numberChar[100],prefix=1;
else if(prefix&&value%100!=0) cn+=numberChar[0],prefix=0;
value%=100;
if(value>=10) cn+=numberChar[value/10]+numberChar[10];
else if(prefix&&value%10!=0) cn+=numberChar[0];
value%=10;
if(value>=1) cn+=numberChar[value];
}
以及将三个数级整合起来的代码
这里为了方便实现,将 numberChar 改为了 map 容器储存,并且补充了 charNumber 来储存反向的信息
bool ToChar(string &cn,long long int value){
if(value<0) cn="负",value=-value;
if(value>>31) return false;
else cn="";
int Ge=value%10000,Wan=value/10000%10000,Yi=value/10000/10000;
bool prefix=0;
if(Yi) ToCharInThousand(cn,Yi),cn+=numberChar[100000000],prefix=1;
if(Wan){
if(Wan<1000&&prefix) cn+=numberChar[0];
if(Wan>=10&&Wan<20&&prefix) cn+=numberChar[1];
ToCharInThousand(cn,Wan),cn+=numberChar[10000];
prefix=1;
}
else if(prefix) cn+=numberChar[0],prefix=0;
if(Ge){
if(Ge<1000&&prefix) cn+=numberChar[0];
if(Ge>=10&&Ge<20&&prefix) cn+=numberChar[1];
ToCharInThousand(cn,Ge);
}
return true;
}
最后放出总代码:
NumberRepository.h
#include<string>
#include<map>
using namespace std;
#ifndef NUMBERREPOSITORY
#define NUMBERREPOSITORY
class NumberRepository{
private:
map<int,string> numberChar;
map<string,int> charNumber;
void NumberCharPrepare(){
numberChar[0]="零";
numberChar[1]="一";
numberChar[2]="二";
numberChar[3]="三";
numberChar[4]="四";
numberChar[5]="五";
numberChar[6]="六";
numberChar[7]="七";
numberChar[8]="八";
numberChar[9]="九";
numberChar[10]="十";
numberChar[100]="百";
numberChar[1000]="千";
numberChar[10000]="万";
numberChar[100000000]="亿";
}
void CharNumberPrepare(){
charNumber["零"]=0;
charNumber["一"]=1;
charNumber["二"]=2;
charNumber["三"]=3;
charNumber["四"]=4;
charNumber["五"]=5;
charNumber["六"]=6;
charNumber["七"]=7;
charNumber["八"]=8;
charNumber["九"]=9;
charNumber["十"]=10;
charNumber["百"]=100;
charNumber["千"]=1000;
charNumber["万"]=10000;
charNumber["亿"]=100000000;
}
bool FindChar(int &number,string num){
if( charNumber.find(num)==charNumber.end() ) return 0;//找不到
number=charNumber[num];
return true;
}
bool FormatChar(string &num){
int temporary[3];
for(int i=0;i<=num.size()-2;i+=2)
if( !FindChar(temporary[i>>1],num.substr(i,2)) ) return false;//字符合法性检验
if( num.size()==2 ) num=numberChar[0]+num;//一个字,前补零,十因为特殊性也可以这样处理
else if( num.size()==4 ){
if(temporary[0]==10&&temporary[1]==10) return false;//两个数不同时为十
if(temporary[0]==10) num=numberChar[1]+num.substr(2,2);//十几的形式
else if(temporary[1]==10) num=num.substr(0,2)+numberChar[0];//几十的形式
}
else if( num.size()==6 ){
if( temporary[0]==10 || temporary[1]!=10 || temporary[2]==10 ) return false;//首尾不能为十,中间一定要为十
num=num.substr(0,2)+num.substr(4,2);//去掉中间
}
return true;
}
void ToCharInThousand(string &cn,int value){
if(value<20){
if(value<=10) cn+=numberChar[value];
else cn+=numberChar[10]+numberChar[value-10];
return ;
}
bool prefix=0;
if(value>=1000) cn+=numberChar[value/1000]+numberChar[1000],prefix=1;
else if(prefix&&value%1000!=0) cn+=numberChar[0],prefix=0;
value%=1000;
if(value>=100) cn+=numberChar[value/100]+numberChar[100],prefix=1;
else if(prefix&&value%100!=0) cn+=numberChar[0],prefix=0;
value%=100;
if(value>=10) cn+=numberChar[value/10]+numberChar[10];
else if(prefix&&value%10!=0) cn+=numberChar[0];
value%=10;
if(value>=1) cn+=numberChar[value];
}
public:
NumberRepository(){//初始化赋值
NumberCharPrepare();
CharNumberPrepare();
}
~NumberRepository() {}
bool ToChar(string &cn,long long int value){
if(value<0) cn="负",value=-value;
if(value>>31) return false;
else cn="";
int Ge=value%10000,Wan=value/10000%10000,Yi=value/10000/10000;
bool prefix=0;
if(Yi) ToCharInThousand(cn,Yi),cn+=numberChar[100000000],prefix=1;
if(Wan){
if(Wan<1000&&prefix) cn+=numberChar[0];
if(Wan>=10&&Wan<20&&prefix) cn+=numberChar[1];
ToCharInThousand(cn,Wan),cn+=numberChar[10000];
prefix=1;
}
else if(prefix) cn+=numberChar[0],prefix=0;
if(Ge){
if(Ge<1000&&prefix) cn+=numberChar[0];
if(Ge>=10&&Ge<20&&prefix) cn+=numberChar[1];
ToCharInThousand(cn,Ge);
}
return true;
}
bool ToNumber(int &value,string name){
bool negative=0;
if(name.substr(0,2)=="负") negative=1,name=name.substr(2);//先判定是否是负数
if( !FormatChar(name) ) return false;//失败
int ten,base;
FindChar( ten,name.substr(0,2) );
FindChar( base,name.substr(2,2) );
value=ten*10+base;
if(negative) value=-value;
return true;
}
};
#endif
三、值库(ValueRepository)
内部实例化了变量库与数字库,大部分方法都与两者相同,只需要使用到两者的方法即可
而唯一增加的即使对右值的查询
bool ValueFind(int &value,string name){
if( numberRepository.ToNumber(value,name) ) return true;
return variableRepository.VariableShow(value,name);
}
一样为先判定是否是数字,再判定是否是变量。通过引用返回具体数值
直接给出代码:
ValueRepository.h
#include "VariableRepository.h"
#include "NumberRepository.h"
#ifndef VALUEREPOSITORY
#define VALUEREPOSITORY
class ValueRepository{
private:
VariableRepository variableRepository;
NumberRepository numberRepository;
public:
ValueRepository() {}
~ValueRepository() {}
bool ToChar(string &cn,int value){
return numberRepository.ToChar(cn,value);
}
bool ToNumber(int &value,string name){
return numberRepository.ToNumber(value,name);
}
bool VariableApply(string name){
return variableRepository.VariableApply(name);
}
bool VariableDelete(string name){
return variableRepository.VariableDelete(name);
}
bool VariableAssign(string name,int value){
return variableRepository.VariableAssign(name,value);
}
bool VariableApplyAssign(string name,int value){
return variableRepository.VariableApplyAssign(name,value);
}
bool VariableAdd(string name,int value){
return variableRepository.VariableAdd(name,value);
}
bool VariableSubtract(string name,int value){
return variableRepository.VariableSubtract(name,value);
}
bool VariableMultiply(string name,int value){
return variableRepository.VariableMultiply(name,value);
}
bool VariableDevide(string name,int value){
return variableRepository.VariableDivide(name,value);
}
bool VariableModule(string name,int value){
return variableRepository.VariableModule(name,value);
}
bool VariableRemainder(string name,int value){
return variableRepository.VariableRemainder(name,value);
}
bool VariableShow(int &value,string name){
return variableRepository.VariableShow(value,name);
}
bool ValueFind(int &value,string name){
if( numberRepository.ToNumber(value,name) ) return true;
return variableRepository.VariableShow(value,name);
}
};
#endif
四、错误处理库(ErrorRepository.h)
为使得 World 作为唯一与用户交互的类,错误处理库使用传入 string 类引用的方法
然后,可以根据错误类型(errorType)为整数的特性,直接用 vector 储存需要返回的 string
而同时,将关键字(Keyword)直接存到 ErrorRepository 中,可以避免 World 冗长,也方便查找
因此 ErrorRepository 在处理错误抛出的同时,还应开一个 vector 储存所有非数字关键字,到时候直接查询这个库来避免冲突关键字
比较简单,直接给出代码:
ErrorRepository.h
#include<vector>
#include<string>
using namespace std;
#ifndef ERRORREPOSITORY
#define ERRORREPOSITORY
class ErrorRepository{
private:
vector<string> keywordRepository,errorWordRepository;
void KeywordRepositoryPrepare(){
keywordRepository.push_back("增加");
keywordRepository.push_back("减少");
keywordRepository.push_back("乘以");
keywordRepository.push_back("除以");
keywordRepository.push_back("取模");
keywordRepository.push_back("取余");
keywordRepository.push_back("看看");
keywordRepository.push_back("等于");
keywordRepository.push_back("整数");
keywordRepository.push_back("删除");
}
void ErrorWordRepositoryPrepare(){
errorWordRepository.push_back("");
errorWordRepository.push_back("变量不存在");
errorWordRepository.push_back("变量已申请");
errorWordRepository.push_back("数字错误");
errorWordRepository.push_back("语句无法识别");
errorWordRepository.push_back("与关键字冲突");
errorWordRepository.push_back("数字超限");
errorWordRepository.push_back("零不得为除数");
}
public:
ErrorRepository(){
KeywordRepositoryPrepare();
ErrorWordRepositoryPrepare();
}
~ErrorRepository() {}
void ErrorOutput(string &output,int errorType){
if(errorType>=0&&errorType<errorWordRepository.size())
output=errorWordRepository[errorType];
else output="未知错误";
}
bool IsKeyword(string name){
for(int i=0;i<keywordRepository.size();i++)
if(keywordRepository[i]==name) return 1;
return 0;
}
};
#endif
五、世界(World)
为避免大部分码量又耗费在划分关键字上,直接构造方法 OrderBreakDown 将指令分解,并存在指令的暂存器 orderRegister 内
void OrderBreakDown(string order){//将指令按空格分解
orderRegister.clear();//先清空暂存器
while(order.find(" ")!=string::npos){
orderRegister.push_back( order.substr(0,order.find(" ")) );
order=order.substr( order.find(" ")+1 );
}
if(order.size()!=0) orderRegister.push_back(order);
}
而如此一来,之前用以分解指令的 Update_string,Apply_string,Show_string 方法都没有存在的必要了
修改 World 的结构,使之直接在 Understand 方法中进行分装:
void Understand(int &errorType,string &answer,string sentence){
errorType=0;//初始化无错误
answer="";//初始化输出为空
OrderBreakDown(sentence);//分解指令
if(orderRegister.size()<=1){//除空格外,只含不超过一个内容,指令非法
errorType=4;
return ;
}
if(orderRegister.size()==4&&orderRegister[0]=="整数"){
if(orderRegister[2]!="等于") errorType=4;
//分解为四节的,一定需为“整数 <变量> 等于 <值>”的形式
int value;
if( !valueRepository.ValueFind(value,orderRegister[3]) ) errorType=3;
else ApplyAssign(errorType,orderRegister[1],value);
}
else if(orderRegister.size()==2){
if(orderRegister[0]=="看看") Print(errorType,answer,orderRegister[1]);
else if(orderRegister[0]=="整数") Apply(errorType,orderRegister[1]);
else if(orderRegister[0]=="删除") Delete(errorType,orderRegister[1]);
}
else if(orderRegister.size()==3){
int value;
if( !valueRepository.ValueFind(value,orderRegister[2]) ) errorType=3;
else Update(errorType,orderRegister[0],value);
}
else errorType=4;
}
这里的 Update 是将所有对变量值操作的函数,加入到一个新的方法中进行分发
void Update(int &errorType,string name,int value){//变量值发生变化的操作
if(orderRegister[1]=="增加") Add(errorType,name,value);
if(orderRegister[1]=="减少") Subtract(errorType,name,value);
if(orderRegister[1]=="乘以") Multiply(errorType,name,value);
if(orderRegister[1]=="除以") Devide(errorType,name,value);
if(orderRegister[1]=="取模") Module(errorType,name,value);
if(orderRegister[1]=="取余") Remainder(errorType,name,value);
}
考虑到了 OrderBreakDown 方法的引入,对变量的值修改的方法书写起来就会方便许多,以增加操作为例:
void Add(int &errorType,string name,int value){
if( !valueRepository.VariableAdd(name,value) ) errorType=1;
}
而较为特殊的就是除以、取模、取余操作,其均需要先进行特判:除数不为0,以除以操作为例:
void Devide(int &errorType,string name,int value){
if(value==0) errorType=7;//0 不能作为除数,下同
else if( !valueRepository.VariableDevide(name,value) ) errorType=1;
}
由对于变量库的修改,对应的 World 类中也需要增加 ApplyAssign 方法
void ApplyAssign(int &errorType,string name,int value){
errorType=0;
if( IsConflict(name) ) errorType=5;//与关键字冲突
else if( !valueRepository.VariableApplyAssign(name,value) ) errorType=2;//申请失败,返回2(变量已申请)
}
其余的方法变化不大,这里直接给出总代码:
World.h
#include "ValueRepository.h"
#include "ErrorRepository.h"
#include<vector>
#include<string>
#include<iostream>
using namespace std;
#ifndef WORLD
#define WORLD
class World{
private:
ValueRepository valueRepository;
ErrorRepository errorRepository;
vector<string> orderRegister;
bool IsConflict(string name){
int value;
if( valueRepository.ToNumber(value,name) ) return 1;
return errorRepository.IsKeyword(name);
}
bool Input(string &sentence){
return getline(cin,sentence);
}
void OrderBreakDown(string order){//将指令按空格分解
orderRegister.clear();//先清空暂存器
while(order.find(" ")!=string::npos){
orderRegister.push_back( order.substr(0,order.find(" ")) );
order=order.substr( order.find(" ")+1 );
}
if(order.size()!=0) orderRegister.push_back(order);
}
void Add(int &errorType,string name,int value){
if( !valueRepository.VariableAdd(name,value) ) errorType=1;
}
void Subtract(int &errorType,string name,int value){
if( !valueRepository.VariableSubtract(name,value) ) errorType=1;
}
void Multiply(int &errorType,string name,int value){
if( !valueRepository.VariableMultiply(name,value) ) errorType=1;
}
void Devide(int &errorType,string name,int value){
if(value==0) errorType=7;//0 不能作为除数,下同
else if( !valueRepository.VariableDevide(name,value) ) errorType=1;
}
void Module(int &errorType,string name,int value){
if(value==0) errorType=7;
else if( !valueRepository.VariableModule(name,value) ) errorType=1;
}
void Remainder(int &errorType,string name,int value){
if(value==0) errorType=7;
else if( !valueRepository.VariableRemainder(name,value) ) errorType=1;
}
void Assign(int &errorType,string name,int value){
if( !valueRepository.VariableAssign(name,value) ) errorType=1;
}
void Apply(int &errorType,string name){
if( IsConflict(name) ) errorType=5;//与关键字冲突
else if( !valueRepository.VariableApply(name) ) errorType=2;//申请失败,返回2(变量已申请)
}
void ApplyAssign(int &errorType,string name,int value){
errorType=0;
if( IsConflict(name) ) errorType=5;//与关键字冲突
else if( !valueRepository.VariableApplyAssign(name,value) ) errorType=2;//申请失败,返回2(变量已申请)
}
void Print(int &errorType,string &value,string name){
int data;
if( !valueRepository.VariableShow(data,name) ) errorType=1;
else if( !valueRepository.ToChar(value,data) ) errorType=6;//数字超限
}
void Delete(int &errorType,string name){
if( !valueRepository.VariableDelete(name) ) errorType=1;
}
void Update(int &errorType,string name,int value){//变量值发生变化的操作
if(orderRegister[1]=="增加") Add(errorType,name,value);
if(orderRegister[1]=="减少") Subtract(errorType,name,value);
if(orderRegister[1]=="乘以") Multiply(errorType,name,value);
if(orderRegister[1]=="除以") Devide(errorType,name,value);
if(orderRegister[1]=="取模") Module(errorType,name,value);
if(orderRegister[1]=="取余") Remainder(errorType,name,value);
}
void Understand(int &errorType,string &answer,string sentence){
errorType=0;//初始化无错误
answer="";//初始化输出为空
OrderBreakDown(sentence);//分解指令
if(orderRegister.size()<=1){//除空格外,只含不超过一个内容,指令非法
errorType=4;
return ;
}
if(orderRegister.size()==4&&orderRegister[0]=="整数"){
if(orderRegister[2]!="等于") errorType=4;
//分解为四节的,一定需为“整数 <变量> 等于 <值>”的形式
int value;
if( !valueRepository.ValueFind(value,orderRegister[3]) ) errorType=3;
else ApplyAssign(errorType,orderRegister[1],value);
}
else if(orderRegister.size()==2){
if(orderRegister[0]=="看看") Print(errorType,answer,orderRegister[1]);
if(orderRegister[0]=="整数") Apply(errorType,orderRegister[1]);
if(orderRegister[0]=="删除") Delete(errorType,orderRegister[1]);
}
else if(orderRegister.size()==3){
int value;
if( !valueRepository.ValueFind(value,orderRegister[2]) ) errorType=3;
else Update(errorType,orderRegister[0],value);
}
else errorType=4;
}
public:
World() {}
~World() {}
void Run(){
string order,answer;
int errorType;
while( Input(order) ){
if(order=="退出") break;
Understand(errorType,answer,order);
if(errorType!=0) errorRepository.ErrorOutput(answer,errorType);
if(answer.size()) cout<<answer<<endl;
}
}
};
#endif
六、编译脚本
现在的新代码中,包含了以下的六个部分
- ErrorRepository.h
- NumberRepository.h
- VariableRepository.h
- ValueRepository.h
- World.h
- baihua-lang.cpp
其中,编译 2、3 为编译 4 的先决条件;编译 1、4 为编译 5 的先决条件;编译 5 为编译 6 的先决条件
故此编写编译脚本时因注重以上顺序
编译脚本.bat
@echo off
title 编译脚本
if exist baihua-lang.exe (
echo 程序 baihua-lang.exe 已存在
pause>nul
exit
)
if not exist baihua-lang.cpp (
echo 源代码 baihua-lang.cpp 丢失
pause>nul
exit
)
if not exist World.h.gch (
if not exist World.h (
echo 源代码 World.h 丢失
pause>nul
exit
)
if not exist ErrorRepository.h.gch (
if exist ErrorRepository.h (g++ ErrorRepository.h) else (
echo 源代码 ErrorRepository.h 丢失
pause>nul
exit
)
)
if not exist ValueRepository.h.gch (
if not exist ValueRepository.h (
echo 源代码 ValueRepository.h 丢失
pause>nul
exit
)
if not exist VariableRepository.h.gch (
if exist VariableRepository.h (g++ VariableRepository.h) else (
echo 源代码 VariableRepository.h 丢失
pause>nul
exit
)
)
if not exist NumberRepository.h.gch (
if exist NumberRepository.h (g++ NumberRepository.h) else (
echo 源代码 NumberRepository.h 丢失
pause>nul
exit
)
)
g++ ValueRepository.h
)
g++ World.h
)
g++ -o baihua-lang.exe baihua-lang.cpp
echo 编译完成
pause>nul
七、思考题想法
对于分支与循环语句的实现,均需要用一个逻辑语句的储存器,和一个语句的储存器实现
对于比较简单的分支语句,需要先判定逻辑语句是否正确,再根据逻辑的结果,对应执行语句
而循环语句分为“当型”与“直到型”,均需要储存下语句。
“当型”先判定逻辑语句,当逻辑语句的值正确时,重复执行循环语句,直到逻辑语句为错误
“直到型”先执行循环语句,再判定逻辑语句,当逻辑语句的值错误时,重复执行循环语句,直到正确
而为避免死循环导致 baihua-lang.exe 崩溃,需设定一个循环次数的上界,当达到上届后自动抛错“循环溢出”
因此,为实现上述功能,最重要的包括两点:
- 实现“两栖式”读取指令:既可从外界读入,也可从语句储存器中读入
- 实现逻辑判断能力
其中逻辑判断能力实现比较复杂,例如以下情况:
如果
钱包 大于 五
且
钱包 小于 十
或
微信 大于等于 六
异或
银行卡 小于等于 八
或
非
支付宝 等于 三
则
......
因此,实现分支与循环语句需要较大的代码量
People &Me=FeiMa;
Me.say("关于此,我确信已发现了一种美妙的证法,可惜这里空白的地方太小,写不下。");
我已想到了一个比较可能的实现方法,等我比较空闲了以后再来实现此功能