• 2020面向对象程序设计寒假作业3 题解


    作业描述 详情
    这个作业属于哪个课程 班级链接
    这个作业要求在哪里 作业要求
    这个作业的目标 编程题:
    继续完成作业二的编程题。
    1. 优化架构,思考代码的拓展性,比如我需要增加其他功能,如选择,循环语句怎么办。
    2. 思考:可以参考现有的编程语言,把这些语言的内容加入。如选择、循环语句、函数、或者扩大数字范围,支持负数等。
    作业正文 2020面向对象程序设计寒假作业3 题解
    其他参考文献 C++之vector类型的使用和迭代器使用

    参考 本人第二次作业 后,重新规划了架构


    题目要求

    1. 继续完成作业二的编程题。
    2. 优化架构,思考代码的拓展性,比如我需要增加其他功能,如选择,循环语句怎么办。
    3. 思考:可以参考现有的编程语言,把这些语言的内容加入。如选择、循环语句、函数、或者扩大数字范围,支持负数等。

    优化目标

    1. 在一定程度上减少码量
    2. 增加一定的封装,使得代码可读性提高
    3. 增加对负数的处理
    4. 尽可能使用引用来实现传值,方便后续的拓展
    5. 增加对其它运算的支持

    思考过程

    1. 在实现作业二的过程中,发现 World 类中,出现了较多的错误抛出方法,因此构建一个新的类 ErrorRepository 来专门实现错误抛出
    2. 在实现作业二的过程中,发现赋值语句的右侧,可以是变量或者数字。最后如果是返回数值,则一定是这两者的值之一。对于在代码中多次出现:试探是否是数值、再试探是否是变量,这一重复操作。故此,将两个类用一个新的类 ValueRepository 进行封装。在该类中实现方法,进行查询
    3. 通过查询 相关资料 ,学习到可以使用迭代器实现变量的操作
    4. 拓展数域至负数,实际上就是考虑“负”以及对负号的处理
    5. 在实现作业二的过程中发现,大部分代码量花费在对语句的划分上,直接构造一个新的方法来实现对语句的划分

    因此开始构建:


    一、变量库(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 范围内

    根据本人翻阅小学数学书,大数的读法与写法,其中介绍了大数的读法:

    1. 根据中国的读法,四个数位为一级
    2. 从小到大,数级为:个、万、亿等(其余不在 int 范围内)
    3. 读数时从大的数级往小读
    4. 若存在更大数级的情况下,本数级若不满四位,且前一数级不全为 0 的话,应加前缀零。如:20147,读作:两万零一百四十七
    5. 最高位数级若介于 11 至 19 ,应读作“十*”的形式
    6. 凡是非最高位数级, 11 至 19 均应读作“一十*”的形式
    7. 数级内,若后缀全为零的不再补充后缀。如:2100300,读作:二百一十万零三百
    8. 数级内,两非零数位间存在零,读且仅读一个零。如: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
    

    六、编译脚本

    现在的新代码中,包含了以下的六个部分

    1. ErrorRepository.h
    2. NumberRepository.h
    3. VariableRepository.h
    4. ValueRepository.h
    5. World.h
    6. 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 崩溃,需设定一个循环次数的上界,当达到上届后自动抛错“循环溢出”

    因此,为实现上述功能,最重要的包括两点:

    1. 实现“两栖式”读取指令:既可从外界读入,也可从语句储存器中读入
    2. 实现逻辑判断能力

    其中逻辑判断能力实现比较复杂,例如以下情况:

    如果
    钱包 大于 五
    且
    钱包 小于 十
    或
    微信 大于等于 六
    异或
    银行卡 小于等于 八
    或
    非
    支付宝 等于 三
    则
    ......
    

    因此,实现分支与循环语句需要较大的代码量

    People &Me=FeiMa;
    Me.say("关于此,我确信已发现了一种美妙的证法,可惜这里空白的地方太小,写不下。");
    

    我已想到了一个比较可能的实现方法,等我比较空闲了以后再来实现此功能

  • 相关阅读:
    IXmlSerializable With WCFData Transfer in Service Contracts
    Difference Between XmlSerialization and BinarySerialization
    Using XmlSerializer (using Attributes like XmlElement , XmlAttribute etc ) Data Transfer in Service Contracts
    Introducing XML Serialization
    Version Tolerant Serialization
    Which binding is bestWCF Bindings
    Data Transfer in Service Contracts
    DataContract KnownTypeData Transfer in Service Contracts
    Using the Message ClassData Transfer in Service Contracts
    DataContract POCO SupportData Transfer in Service Contracts
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/12300895.html
Copyright © 2020-2023  润新知