zoukankan      html  css  js  c++  java
  • 洛谷 P3695 CYaRon!语 题解 【模拟】【字符串】

    大模拟好啊!

    万一远古计算机让我写个解释器还真是得爆零了呢。

    题目背景

    「千歌です」(我是千歌)、「曜です」(我是曜)、「ルビィです」(我是露比)、「3人合わせて、We are CYaRon! よろしくね!」(三人在一起,我们是CYaRon!多多指教哦!)

    CYaRon!的三人在学习了编程之后,决定发明一种自己的编程语言,她们称为CYaRon!语。

    (ltt: 明明是我帮她们发明的。)

    可是,因为洛谷评测机这时候突然爆了,ltt没有时间再帮CYaRon!的三位小姐姐写CYaRon!语的解释器了。

    于是ltt就出了这样一道题,然后等着有人交了AC程序就偷走给小姐姐们。

    题目描述

    以下是一个典型的CYaRon! 语程序。

    { vars
        chika:int
        you:int
        ruby:array[int, 1..2]
        i:int
    }
    # 以上变量默认值均为0
    # 变量名只可是英文字母。
    
    # yosoro语句可以输出一个数字,随后跟一个空格。
    :yosoro 2
    # 输出2和一个空格(以下不再提到空格)。
    
    # set语句可以为变量赋值。
    # 运算符只支持加减号即可。
    :set chika, 1
    :set you, 2
    :yosoro chika + you
    # 上一条语句将输出3
    
    # 以下的判断语句均使用以下的格式:
    # 操作符,表达式,表达式
    # 例如eq, a, 1即C语言中 a==1
    # 所有操作符包括: lt: < gt: > le: <= ge: >= eq: == neq: !=
    
    # 日本来的CYaRon三人没法正确地发出if这个音,因此她们就改成了ihu。
    { ihu eq, chika, 1
        :set you, 3
        :yosoro 1
    }
    # 输出1
    # 以上是ihu语句,无需支持else。
    
    # hor语句同理,
    # for i=1 to you如下
    { hor i, 1, you
        :yosoro i
    }
    # 输出1 2 3
    
    # 如下是while和数组的使用方法。
    :set i, 1
    { while le, i, 2
        :yosoro i
        :set ruby[i], i+1
        :yosoro ruby[i]
        :set i, i+1
    }
    # 输出1 2 2 3
    
    # 数组不会出现嵌套,即只会有a[i]、a[i+2]而不会有类似于a[i+b[i]]这样的。
    
    # CYaRon语的最后一行,一定是一个换行。
    

    你的任务是写一个CYaRon!语的解释器,实现输入CYaRon!语的程序,解释之执行后输出执行结果。

    输入输出格式

    输入格式:

    输入文件全部为CYaRon!语程序,最后一行保证是个空行。

    请处理输入的时候,一直读到EOF为止。

    输出格式:

    该CYaRon!语程序的执行结果。

    具体上,是该CYaRon!语程序所有:yosoro语句的输出。

    输入输出样例

    输入样例#1:

    { vars
        a:int
        b:int
    }
    
    :set a, 1
    :set b, 2
    :yosoro a+b
    

    输出样例#1:

    3
    

    说明

    对数据做出以下保证:

    1. 输入数据一定是合法的CYaRon!语程序,不包含注释,代码、缩进风格 (四个空格)与上述样例相同。但不保证逗号、运算符前面的空格数量和有无一定相同
    2. 变量名在10个字符以下,仅包含小写英文,数组最大大小为1000,变量最多50个,所有表达式的运算结果,包括变量的值一定在int范围内。 (但数组可能是类似于[2001..3000]的,下标可能范围为0到1亿)
    3. 所有指令小写。
    4. 该程序一定能够在合理的时间、内存限制内执行完毕。
    5. hor语句执行过程中,循环变量、初始值、结束值不会被循环中的代码改变。
    6. 该程序最多500行

    img

    题解:

    模拟即可。


    以上就是题解。再有其他内容就是字符串的读入了吧。

    下了三组数据才AC,不得不说#10很强。

    在这个题中,函数思想很重要。因为有很多地方会调用相同的内容,甚至有时候有大篇幅相似的两部分可以合在一个函数里再加if判断。

    循环的嵌套是最麻烦的内容,其次是变量求值。还好没有数组套数组(大不了多几个递归),字符串长度开得比较小。变量可以用std::map映射,然后用编号统一存起来。

    对于变量求值而言,一个是单项式求值,一个是多项式(仅加减)求值,其中又要考虑是否是数组的情况。我写了一个getnext(int &i)函数,用来获取从(i)开始的第一个可求的式子。如果a是一个数组,那么a[7]是一个可求的式子而a不是。然后用字符串处理依次考虑正负即可。

    如果经常使用gdb或某些IDE的自带debug器的话,循环嵌套的思路比较容易联想,实现起来比较麻烦废话。使用一个变量tot存储当前做到循环的第几行了,带入内层循环tot不变,循环结束时置tot为en+2(en指循环结束的}字符所在行的前一行)。

    还有一个地方是循环中语句会被使用多遍,这时不能直接通过标准读入,而要把这些语句全部存起来。读一行(空格也读)用到的是gets(char *s),当读到EOF时返回NULL。

    注意这个题的缩进和空格都不确定。所以需要写一个jump(),就是使(i)跳过前面所有的连续空格。还有其他字符的跳过额外写一点也不怎么麻烦。

    感谢自己的坚持。

    Code:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<map>
    #define jump() do{while(s[i]==' ')++i;}while(0)
    using namespace std;
    map<string,int> mp;
    int a[55][1010];
    int cnt;
    int st[55],len[55];
    char s[1000];
    int getnext(int &i)//获得从i开始接下来一段式子的值 i被置为最后一个下标+1
    {
        jump();
        int x=0;
        if(s[i]>='0'&&s[i]<='9')
        {
            for(;s[i]>='0'&&s[i]<='9';++i)
                x=x*10+s[i]-'0';
            return x;
        }
        string ss="";
        for(;s[i]>='a'&&s[i]<='z';++i)
            ss+=s[i];
        int t=mp[ss];
        if(len[t]==1)
            return a[t][0];
        jump();
        ++i;
        int ans=a[t][getnext(i)-st[t]];
        ++i;
        return ans;
    }
    int getstring(int &i)//获得从i开始的一个多项式的值
    {
        int ans=0,flag=1;
        jump();
        while((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')||s[i]=='+'||s[i]=='-')
        {
            flag=(s[i]=='-')?-1:1;
            while(s[i]==' '||s[i]=='+'||s[i]=='-')
                ++i;
            ans+=flag*getnext(i);
            jump();
        }
        return ans;
    }
    void Set()//赋值
    {
        int i=0;
        jump();
        i+=4;
        jump();
        string ss="";
        for(;s[i]>='a'&&s[i]<='z';++i)
            ss+=s[i];
        int t=mp[ss],u=0,v=0;
        if(len[t]==1)
        {
            while(s[i]==' '||s[i]==',')
                ++i;
            a[t][0]=getstring(i);
        }
        else
        {
            ++i;
            u=getstring(i);
            //i是']'
            ++i;
            while(s[i]==' '||s[i]==',')
                ++i;
            a[t][u-st[t]]=getstring(i);
        }
    }
    void print()
    {
        int i=0;
        jump();
        i+=7;
        jump();
        while(s[i]==' '||s[i]==',')
            ++i;
        printf("%d ",getstring(i));
    }
    
    void qaq();
    bool ihu(int ty);
    void hor();
    void whi();
    
    char F[500][100];
    int tot=0;
    
    bool isend()//是否结尾 判断ihu、hor和while是否结束
    {
        if(!tot)
            gets(s);
        else
        {
            int i=0;
            for(;F[tot][i]!='';++i)
                s[i]=F[tot][i];
            s[i]='';
            ++tot;
        }
        int i=0;
        jump();
        return (s[i]=='}');
    }
    
    int main()
    {
        gets(s);
        int i=1,flag=0;
        jump();
        if(s[i]=='v')//如果没有定义就要跳过
    {
        gets(s);
        while(s[0]!='}')
        {
            string ss="";
            int i=0;
            jump();
            for(;s[i]>='a'&&s[i]<='z';++i)
                ss+=s[i];
            mp[ss]=++cnt;
            jump();
            if(s[i+1]=='i')
                st[cnt]=len[cnt]=1;
            else
            {
                i+=10;
                while(s[i]==' '||s[i]==',')
                    ++i;
                //逗号前后的空格
                st[cnt]=getnext(i);
                while(s[i]==' '||s[i]=='.')
                    ++i;
                len[cnt]=getnext(i);
                len[cnt]-=st[cnt]-1;
            }
            gets(s);
        }
    }
        else
            flag=1;
        
        while(flag||gets(s)!=NULL)
        {
            flag=0;
            if(!strlen(s))
                continue;
            qaq();
            tot=0;
        }
        return 0;
    }
    void qaq()//执行语句
    {
        int i=0;
        jump();
        if(s[i]=='{')
        {
            ++i;
            jump();
            if(s[i]=='i')
                ihu(0);
            else if(s[i]=='w')
                whi();
            else
                hor();
        }
        else if(s[i+1]=='s')
            Set();
        else
            print();
    }
    
    bool ihu(int ty)
    {
        int i=0;
        jump();
        ++i;
        jump();
        i+=3+ty*2;
        jump();
        char tmp[2]={s[i],s[i+1]};
        i+=2;
        if(tmp[0]=='n')
            ++i;
        while(s[i]==' '||s[i]==',')
            ++i;
        int x=getstring(i);
        while(s[i]==' '||s[i]==',')
            ++i;
        int y=getstring(i);
        bool sat;
        if(tmp[0]=='e')
            sat=(x==y);
        else if(tmp[0]=='l')
        {
            if(tmp[1]=='t')
                sat=(x<y);
            else
                sat=(x<=y);
        }
        else if(tmp[0]=='n')
            sat=(x!=y);
        else
        {
            if(tmp[1]=='t')
                sat=(x>y);
            else
                sat=(x>=y);
        }
        if(ty)
            return sat;
        int br=1;
        if(!sat)
            while(1)
            {
                if(isend()&&br==1)
                    return 0;
                i=0;
                jump();
                if(s[i]=='{')
                    ++br;
                if(s[i]=='}')
                    --br;
            }
        else
        {
            while(1)
            {
                if(isend()&&br==1)
                    return 0;
                if(!strlen(s))
                    continue;
                qaq();
            }
        }
    }
    void hor()
    {
        int i=0;
        jump();
        ++i;
        jump();
        i+=3;
        jump();
        string ss="";
        for(;s[i]>='a'&&s[i]<='z';++i)
            ss+=s[i];
        int t=mp[ss];
        int *ii,u;//用指针引用值更加方便
        if(len[t]==1)
            ii=&a[t][0];
        else
        {
            ++i;
            u=getstring(i);
            ii=&a[t][u-st[t]];
        }
        while(s[i]==' '||s[i]==',')
            ++i;
        int from=getstring(i);
        while(s[i]==' '||s[i]==',')
            ++i;
        int to=getstring(i);
        int st=1,en=0,l=0;
        if(tot)
            st=tot;
        int br=1;
        while(1)
        {
            if(isend()&&br==1)//注意不要找到别人的右括号了 下同
            {
                if(tot)
                    en=tot-2;//en是右括号上面一行相对st(1)的编号
                else
                    en=l;
                break;
            }
            if(!strlen(s))//注意空串如果跳过会方便一些
                continue;
            ++l;
            i=0;
            jump();
            if(s[i]=='{')
                ++br;
            if(s[i]=='}')
                --br;
            if(!tot)
            {
                i=0;
                for(;s[i]!='';++i)
                    F[l][i]=s[i];
                F[l][i]='';
            }
        }
        for(*ii=from;*ii<=to;++(*ii))
        {
            tot=st;
            while(tot<=en)
            {
                i=0;
                for(;F[tot][i]!='';++i)
                    s[i]=F[tot][i];
                s[i]='';
                ++tot;
                qaq();
            }
        }
        tot=en+2;
    }
    
    
    void whi()
    {
        int i=0;
        char p[1000];
        for(;s[i]!='';++i)
            p[i]=s[i];
        p[i]='';
        int st=0,en=0,l=0;
        if(tot)//最外层不需要处理这里
        {
            st=tot-1;
            ++tot;
        }
    
        int br=1;
        while(1)
        {
            if(isend()&&br==1)
            {
                if(tot)
                    en=tot-2;
                else
                    en=l;
                break;
            }
            if(!strlen(s))
                continue;
    
            i=0;
            ++l;
            jump();
            if(s[i]=='{')
                ++br;
            if(s[i]=='}')
                --br;
            if(!tot)
            {
                i=0;
                for(;s[i]!='';++i)
                    F[l][i]=s[i];
                F[l][i]='';
            }
        }
    
        while(1)
        {
            tot=st+1;
            i=0;
            for(;p[i]!='';++i)
                s[i]=p[i];
            s[i]='';
            if(!ihu(1))
            {
                tot=en+2;
                return;
            }
    
            while(tot<=en)
            {
                i=0;
                for(;F[tot][i]!='';++i)
                    s[i]=F[tot][i];
                s[i]='';
                ++tot;
                qaq();
            }
        }
    }
    
  • 相关阅读:
    第四百九十六天 how can I 坚持
    第四百九十四、五天 how can I 坚持
    第四百九十三天 how can I 坚持
    第四百九十二天 how can I 坚持
    第四百九十一天 how can I 坚持
    第四百九十天 how can I 坚持
    第四百八十九天 how can I 坚持
    第四百八十八天 how can I 坚持
    第四百八十七天 how can I 坚持
    第四百八十六天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/wjyyy/p/lg3695.html
Copyright © 2011-2022 走看看