题解 P3695 【CYaRon!语】

wjyyy

2019-02-15 07:40:33

Solution

## 题解: 模拟即可。 --- 再有其他内容就是字符串的读入了吧。 下了三组数据才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: ```cpp #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]!='\0';++i) s[i]=F[tot][i]; s[i]='\0'; ++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]!='\0';++i) F[l][i]=s[i]; F[l][i]='\0'; } } for(*ii=from;*ii<=to;++(*ii)) { tot=st; while(tot<=en) { i=0; for(;F[tot][i]!='\0';++i) s[i]=F[tot][i]; s[i]='\0'; ++tot; qaq(); } } tot=en+2; } void whi() { int i=0; char p[1000]; for(;s[i]!='\0';++i) p[i]=s[i]; p[i]='\0'; 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]!='\0';++i) F[l][i]=s[i]; F[l][i]='\0'; } } while(1) { tot=st+1; i=0; for(;p[i]!='\0';++i) s[i]=p[i]; s[i]='\0'; if(!ihu(1)) { tot=en+2; return; } while(tot<=en) { i=0; for(;F[tot][i]!='\0';++i) s[i]=F[tot][i]; s[i]='\0'; ++tot; qaq(); } } } ```