【洛谷P3695】CYaRon!语

模拟

题目大意:

给定一个 CYaRon 语言的程序,你需要模拟它的运行过程,输出它的输出。

需支持整形及整形数组,for、if、while 语句,赋值语句和输出语句。表达式只有加减法,没有数组嵌套。

题目链接

题解:

按题意模拟即可。

这种题使用 C++ 的话不如别的语言方便,很多东西需要手动实现。比如本题需要实现一个简单的表达式求值功能。

这种题先列个总框架,然后根据框架一步一步实现即可。没有什么别的好说的,注意细节。

写大模拟有益身心

Code:

/*
By mrsrz
2019-10-09
*/
#include<iostream>
#include<vector>
#include<cctype>
#include<string>
#include<map>
#include<cstdlib>
#include<stack>
#include<utility>
#include<cstdio>
using namespace std;
/*
 * 基本构思:
 * 代码基本预处理,运算符之间先加上空格方便处理
 * 用链式结构存储语句块
 * 以递归的方式处理循环语句内容
 * 表达式处理写一个单独代码
 * 运行一个语句块的过程写成函数,方便直接递归调用
 */
// 一个常量用三个元素的数组表示如下: {类型 0 常数  1 变量  2 数组, 常数数值/变量编号, 数组下标对应的表达式在表达式池的标号} 以下表示时都以这样的格式
map<string,int>NameToId;//通过变量名找到存储时的下标
struct Var{
    string Name;
    int tp;//0: 变量 1: 数组
    int val;
    struct Array{
        int L,R;
        vector<int>V;
        inline Array(int l=0,int r=0){
            L=l,R=r;
            V.resize(r-l+1);
        }
        inline int&operator[](int x){
            return V[x-L];
        }
    }A;
}var[55];

inline int get_(string s){// 比较类型的英文转化为数字
    if(s=="lt")return 1;
    if(s=="gt")return 2;
    if(s=="le")return 3;
    if(s=="ge")return 4;
    if(s=="eq")return 5;
    if(s=="neq")return 6;
    exit(5);
}

void getnext(int*,string&);

inline int get(int*);

struct EXPR{
    string s;
    vector<pair<pair<int,int>,int> >num;
    vector<int>fh;// 0: +  1: -
    inline void compile(){
        while(s[0]!='-'&&!isdigit(s[0])&&!isalpha(s[0]))s.erase(0,1);
        if(s[0]=='-')s='0'+s;
        while(1){
            int A[3];
            getnext(A,s);
            num.push_back(make_pair(make_pair(A[0],A[1]),A[2]));
            while(!s.empty()&&s[0]!='-'&&s[0]!='+')s.erase(0,1);
            if(s.empty())break;
            fh.push_back(s[0]=='-');
            s.erase(0,1);
        }
    }
    inline int operator()(){
        int A[3];
        A[0]=num[0].first.first,A[1]=num[0].first.second,A[2]=num[0].second;
        int ret=get(A);
        for(int it=0;it<fh.size();++it){
            A[0]=num[it+1].first.first,A[1]=num[it+1].first.second,A[2]=num[it+1].second;
            int val=get(A);
            if(fh[it])ret-=val;else ret+=val;
        }
        return ret;
    }
}Pool[100005];// 给数组下标的表达式预留的池子。数组下标可以是表达式的要求一开始没看见

int topPool;

inline int get(int*a){
    if(a[0]==0)return a[1];
    if(a[0]==1)return var[a[1]].val;
    return var[a[1]].A[Pool[a[2]]()];
}

inline int&getaddress(int*a){// 获取变量/数组元素的地址
    if(a[0]==0)exit(1);
    if(a[0]==1)return var[a[1]].val;
    return var[a[1]].A[Pool[a[2]]()];
}

struct Boolean{
    int tp;// 比较类型 1 <  2 >  3 <=  4 >=  5 ==  6 !=
    EXPR a,b;
    inline bool operator()(){
        switch(tp){
            case 1:
                return a()<b();
            case 2:
                return a()>b();
            case 3:
                return a()<=b();
            case 4:
                return a()>=b();
            case 5:
                return a()==b();
            case 6:
                return a()!=b();
            default:
                exit(4);
        }
    }
};

struct If{
    Boolean F;
    inline bool operator()(){return F();}
}IF[505];

struct While{
    Boolean F;
    inline bool operator()(){return F();}
}WHILE[505];

struct For{
    int A[3];EXPR B,C;
}FOR[505];

EXPR OUT[505];

struct Set{
    int A[3];EXPR B;
}SET[505];

int TYPE[505];// 1. if  2. for  3. while  4. set  5. output

int BlockId[505];

struct cmdBlock{// 语句块的存储
    vector<int>ids;// 存储依次要运行的行号
    int tp;// 1. if  2. for  3. while  0. main
    int head;// 开头所在位置的行号
    inline void add(int id){ids.push_back(id);}
}Block[505];

int cntLine,cntVar,cntBlo;
string Line[505];// 存储每行的语句,后面调用的时候,直接存储行号并分析语句

void getnext(int*A,string&s){// 从字符串中提取最前面的数字/变量,会对字符串进行处理
    while(!isalpha(s[0])&&!isdigit(s[0])&&s[0]!='-')s.erase(0,1);
    if(isdigit(s[0])||s[0]=='-'){// 常数
        A[0]=A[2]=0;
        int d=0,f=0;
        while(!isdigit(s[0]))f=s[0]=='-',s.erase(0,1);
        while(isdigit(s[0]))d=d*10+(s[0]^'0'),s.erase(0,1);
        if(f)d=-d;
        A[1]=d;
    }else{// 变量
        string name="";
        while(isalpha(s[0]))name+=s[0],s.erase(0,1);
        int id=NameToId[name];
        if(var[id].tp==0){// 变量
            A[0]=1,A[1]=id,A[2]=0;
        }else{// 数组
            string ss="";
            while(s[0]!='[')s.erase(0,1);s.erase(0,1);
            while(s[0]!=']')ss+=s[0],s.erase(0,1);s.erase(0,1);
            A[0]=2,A[1]=id,A[2]=++topPool;
            Pool[topPool].s=ss;
            Pool[topPool].compile();
        }
    }
}

int init_Variable(){// 变量预处理部分,返回值为变量定义结束的行号
    int beg=-1;
    for(int i=1;i<=cntLine;++i){
        string s=Line[i];
        if(s[0]=='{'){
            while(s!=""&&!isalpha(s[0]))s.erase(0,1);
            if(s[0]=='v'&&s[1]=='a'&&s[2]=='r'&&s[3]=='s'){
                beg=i;
                break;
            }
        }
    }
    if(beg==-1)return 0;
    for(int i=beg+1;i<=cntLine;++i){
        string cmd=Line[i];
        if(cmd=="")continue;
        if(cmd[0]=='}')return i;
        ++cntVar;
        Var&now=var[cntVar];
        string name="";
        while(cmd[0]!=':')name+=cmd[0],cmd.erase(0,1);
        now.Name=name;
        NameToId[name]=cntVar;
        cmd.erase(0,1);
        if(cmd[0]=='i'){// 单个变量
            now.tp=0;
        }else{// 数组
            int l=0,r=0;
            while(!isdigit(cmd[0]))cmd.erase(0,1);
            while(isdigit(cmd[0]))l=l*10+(cmd[0]^'0'),cmd.erase(0,1);
            while(!isdigit(cmd[0]))cmd.erase(0,1);
            while(cmd!=""&&isdigit(cmd[0]))r=r*10+(cmd[0]^'0'),cmd.erase(0,1);
            now.tp=1;
            now.A=Var::Array(l,r);
        }
    }
    exit(1);
}

void Work(const cmdBlock&B){// 运行语句块
    for(int x=0;x<B.ids.size();++x){
        int i=B.ids[x];
        switch(TYPE[i]){
            case 1:{
                       if(IF[i]())Work(Block[BlockId[i]]);
                       break;
                   }
            case 3:{
                       while(WHILE[i]())Work(Block[BlockId[i]]);
                       break;
                   }
            case 2:{
                       int&var=getaddress(FOR[i].A);
                       for(var=FOR[i].B();var<=FOR[i].C();++var)Work(Block[BlockId[i]]);
                       break;
                   }
            case 4:{
                       int&var=getaddress(SET[i].A);
                       var=SET[i].B();
                       break;
                   }
            case 5:
                   cout<<OUT[i]()<<' ';
                   break;
            default:
                   exit(2);
        }
    }
}

int main(){
//    freopen("code.txt","r",stdin);
    while(!cin.eof()){
        getline(cin,Line[++cntLine]);
        while(Line[cntLine]!=""&&Line[cntLine][0]==' ')Line[cntLine].erase(0,1);
    }

    int beg=init_Variable()+1;
    stack<int>sta;
    sta.push(0);
    for(int i=beg;i<=cntLine;++i)if(Line[i]!=""){
        string s=Line[i]+" ";// 末尾加空格防止溢出
        if(Line[i][0]=='}')
            sta.pop();
        else
            if(Line[i][0]=='{'){// 解析if/for/while
                Block[sta.top()].add(i);
                while(!isalpha(s[0]))s.erase(0,1);
                char c=s[0];
                while(isalpha(s[0]))s.erase(0,1);
                switch(c){
                    case 'i':{// if
                                 TYPE[i]=1;
                                 string typ="";
                                 while(!isalpha(s[0]))s.erase(0,1);
                                 while(isalpha(s[0]))typ+=s[0],s.erase(0,1);
                                 IF[i].F.tp=get_(typ);
                                 int A[3];
                                 string ss;
                                 while(s[0]!=',')s.erase(0,1);s.erase(0,1);
                                 while(s[0]!=',')ss+=s[0],s.erase(0,1);s.erase(0,1);
                                 IF[i].F.a.s=ss,IF[i].F.b.s=s;
                                 IF[i].F.a.compile();IF[i].F.b.compile();
                                 break;
                             }
                    case 'w':{// while
                                 TYPE[i]=3;
                                 string typ="";
                                 while(!isalpha(s[0]))s.erase(0,1);
                                 while(isalpha(s[0]))typ+=s[0],s.erase(0,1);
                                 WHILE[i].F.tp=get_(typ);
                                 string ss;
                                 while(s[0]!=',')s.erase(0,1);s.erase(0,1);
                                 while(s[0]!=',')ss+=s[0],s.erase(0,1);s.erase(0,1);
                                 WHILE[i].F.a.s=ss,WHILE[i].F.b.s=s;
                                 WHILE[i].F.a.compile();WHILE[i].F.b.compile();
                                 break;
                         }
                    case 'h':{// for
                                 TYPE[i]=2;
                                 string s1;
                                 getnext(FOR[i].A,s);
                                 while(s[0]!=',')s.erase(0,1);s.erase(0,1);
                                 while(s[0]!=',')s1+=s[0],s.erase(0,1);s.erase(0,1);
                                 FOR[i].B.s=s1,FOR[i].C.s=s;
                                 FOR[i].B.compile(),FOR[i].C.compile();
                                 break;
                             }
                    default:exit(3);
                }
                Block[++cntBlo].head=i,Block[cntBlo].tp=TYPE[i];
                BlockId[i]=cntBlo;
                sta.push(cntBlo);
            }else{// 解析set yosoro
                Block[sta.top()].add(i);
                string s=Line[i]+" ";
                while(s[0]!=':')s.erase(0,1);
                s.erase(0,1);
                char c=s[0];
                while(isalpha(s[0]))s.erase(0,1);
                if(c=='y'){// 输出语句
                    TYPE[i]=5;
                    OUT[i].s=s;
                    OUT[i].compile();
                }else{// 赋值语句
                    TYPE[i]=4;
                    getnext(SET[i].A,s);
                    while(s[0]!=',')s.erase(0,1);s.erase(0,1);
                    SET[i].B.s=s;
                    SET[i].B.compile();
                }
            }
    }
    Work(Block[0]);
    return 0;
}