zoukankan      html  css  js  c++  java
  • 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("关于此,我确信已发现了一种美妙的证法,可惜这里空白的地方太小,写不下。");
    

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

  • 相关阅读:
    C#WinForm隐藏窗体关闭按钮的方法
    VPRO工具失败时对输出的一种处理方式
    在linux系统下进行pip升级注意事项
    浏览器遮罩层
    关于手机微信端ios的input不能选中问题解决方案
    微信公众号页面遇到的坑
    移动端微信页面的一些自己爬的坑
    使用JS获取上一页的url地址
    vuejs 入门
    python 学习路程(一)
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/12300895.html
Copyright © 2011-2022 走看看