大模拟好啊!

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

题目背景

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

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

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

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

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

题目描述

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

  1. { vars
  2. chika:int
  3. you:int
  4. ruby:array[int, 1..2]
  5. i:int
  6. }
  7. # 以上变量默认值均为0
  8. # 变量名只可是英文字母。
  9. # yosoro语句可以输出一个数字,随后跟一个空格。
  10. :yosoro 2
  11. # 输出2和一个空格(以下不再提到空格)。
  12. # set语句可以为变量赋值。
  13. # 运算符只支持加减号即可。
  14. :set chika, 1
  15. :set you, 2
  16. :yosoro chika + you
  17. # 上一条语句将输出3
  18. # 以下的判断语句均使用以下的格式:
  19. # 操作符,表达式,表达式
  20. # 例如eq, a, 1即C语言中 a==1
  21. # 所有操作符包括: lt: < gt: > le: <= ge: >= eq: == neq: !=
  22. # 日本来的CYaRon三人没法正确地发出if这个音,因此她们就改成了ihu。
  23. { ihu eq, chika, 1
  24. :set you, 3
  25. :yosoro 1
  26. }
  27. # 输出1
  28. # 以上是ihu语句,无需支持else。
  29. # hor语句同理,
  30. # for i=1 to you如下
  31. { hor i, 1, you
  32. :yosoro i
  33. }
  34. # 输出1 2 3
  35. # 如下是while和数组的使用方法。
  36. :set i, 1
  37. { while le, i, 2
  38. :yosoro i
  39. :set ruby[i], i+1
  40. :yosoro ruby[i]
  41. :set i, i+1
  42. }
  43. # 输出1 2 2 3
  44. # 数组不会出现嵌套,即只会有a[i]、a[i+2]而不会有类似于a[i+b[i]]这样的。
  45. # CYaRon语的最后一行,一定是一个换行。

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

输入输出格式

输入格式:

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

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

输出格式:

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

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

输入输出样例

输入样例#1:

  1. { vars
  2. a:int
  3. b:int
  4. }
  5. :set a, 1
  6. :set b, 2
  7. :yosoro a+b

输出样例#1:

  1. 3

说明

对数据做出以下保证:

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

题解:

模拟即可。


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

下了三组数据才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:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<map>
  5. #define jump() do{while(s[i]==' ')++i;}while(0)
  6. using namespace std;
  7. map<string,int> mp;
  8. int a[55][1010];
  9. int cnt;
  10. int st[55],len[55];
  11. char s[1000];
  12. int getnext(int &i)//获得从i开始接下来一段式子的值 i被置为最后一个下标+1
  13. {
  14. jump();
  15. int x=0;
  16. if(s[i]>='0'&&s[i]<='9')
  17. {
  18. for(;s[i]>='0'&&s[i]<='9';++i)
  19. x=x*10+s[i]-'0';
  20. return x;
  21. }
  22. string ss="";
  23. for(;s[i]>='a'&&s[i]<='z';++i)
  24. ss+=s[i];
  25. int t=mp[ss];
  26. if(len[t]==1)
  27. return a[t][0];
  28. jump();
  29. ++i;
  30. int ans=a[t][getnext(i)-st[t]];
  31. ++i;
  32. return ans;
  33. }
  34. int getstring(int &i)//获得从i开始的一个多项式的值
  35. {
  36. int ans=0,flag=1;
  37. jump();
  38. while((s[i]>='0'&&s[i]<='9')||(s[i]>='a'&&s[i]<='z')||s[i]=='+'||s[i]=='-')
  39. {
  40. flag=(s[i]=='-')?-1:1;
  41. while(s[i]==' '||s[i]=='+'||s[i]=='-')
  42. ++i;
  43. ans+=flag*getnext(i);
  44. jump();
  45. }
  46. return ans;
  47. }
  48. void Set()//赋值
  49. {
  50. int i=0;
  51. jump();
  52. i+=4;
  53. jump();
  54. string ss="";
  55. for(;s[i]>='a'&&s[i]<='z';++i)
  56. ss+=s[i];
  57. int t=mp[ss],u=0,v=0;
  58. if(len[t]==1)
  59. {
  60. while(s[i]==' '||s[i]==',')
  61. ++i;
  62. a[t][0]=getstring(i);
  63. }
  64. else
  65. {
  66. ++i;
  67. u=getstring(i);
  68. //i是']'
  69. ++i;
  70. while(s[i]==' '||s[i]==',')
  71. ++i;
  72. a[t][u-st[t]]=getstring(i);
  73. }
  74. }
  75. void print()
  76. {
  77. int i=0;
  78. jump();
  79. i+=7;
  80. jump();
  81. while(s[i]==' '||s[i]==',')
  82. ++i;
  83. printf("%d ",getstring(i));
  84. }
  85. void qaq();
  86. bool ihu(int ty);
  87. void hor();
  88. void whi();
  89. char F[500][100];
  90. int tot=0;
  91. bool isend()//是否结尾 判断ihu、hor和while是否结束
  92. {
  93. if(!tot)
  94. gets(s);
  95. else
  96. {
  97. int i=0;
  98. for(;F[tot][i]!='\0';++i)
  99. s[i]=F[tot][i];
  100. s[i]='\0';
  101. ++tot;
  102. }
  103. int i=0;
  104. jump();
  105. return (s[i]=='}');
  106. }
  107. int main()
  108. {
  109. gets(s);
  110. int i=1,flag=0;
  111. jump();
  112. if(s[i]=='v')//如果没有定义就要跳过
  113. {
  114. gets(s);
  115. while(s[0]!='}')
  116. {
  117. string ss="";
  118. int i=0;
  119. jump();
  120. for(;s[i]>='a'&&s[i]<='z';++i)
  121. ss+=s[i];
  122. mp[ss]=++cnt;
  123. jump();
  124. if(s[i+1]=='i')
  125. st[cnt]=len[cnt]=1;
  126. else
  127. {
  128. i+=10;
  129. while(s[i]==' '||s[i]==',')
  130. ++i;
  131. //逗号前后的空格
  132. st[cnt]=getnext(i);
  133. while(s[i]==' '||s[i]=='.')
  134. ++i;
  135. len[cnt]=getnext(i);
  136. len[cnt]-=st[cnt]-1;
  137. }
  138. gets(s);
  139. }
  140. }
  141. else
  142. flag=1;
  143. while(flag||gets(s)!=NULL)
  144. {
  145. flag=0;
  146. if(!strlen(s))
  147. continue;
  148. qaq();
  149. tot=0;
  150. }
  151. return 0;
  152. }
  153. void qaq()//执行语句
  154. {
  155. int i=0;
  156. jump();
  157. if(s[i]=='{')
  158. {
  159. ++i;
  160. jump();
  161. if(s[i]=='i')
  162. ihu(0);
  163. else if(s[i]=='w')
  164. whi();
  165. else
  166. hor();
  167. }
  168. else if(s[i+1]=='s')
  169. Set();
  170. else
  171. print();
  172. }
  173. bool ihu(int ty)
  174. {
  175. int i=0;
  176. jump();
  177. ++i;
  178. jump();
  179. i+=3+ty*2;
  180. jump();
  181. char tmp[2]={s[i],s[i+1]};
  182. i+=2;
  183. if(tmp[0]=='n')
  184. ++i;
  185. while(s[i]==' '||s[i]==',')
  186. ++i;
  187. int x=getstring(i);
  188. while(s[i]==' '||s[i]==',')
  189. ++i;
  190. int y=getstring(i);
  191. bool sat;
  192. if(tmp[0]=='e')
  193. sat=(x==y);
  194. else if(tmp[0]=='l')
  195. {
  196. if(tmp[1]=='t')
  197. sat=(x<y);
  198. else
  199. sat=(x<=y);
  200. }
  201. else if(tmp[0]=='n')
  202. sat=(x!=y);
  203. else
  204. {
  205. if(tmp[1]=='t')
  206. sat=(x>y);
  207. else
  208. sat=(x>=y);
  209. }
  210. if(ty)
  211. return sat;
  212. int br=1;
  213. if(!sat)
  214. while(1)
  215. {
  216. if(isend()&&br==1)
  217. return 0;
  218. i=0;
  219. jump();
  220. if(s[i]=='{')
  221. ++br;
  222. if(s[i]=='}')
  223. --br;
  224. }
  225. else
  226. {
  227. while(1)
  228. {
  229. if(isend()&&br==1)
  230. return 0;
  231. if(!strlen(s))
  232. continue;
  233. qaq();
  234. }
  235. }
  236. }
  237. void hor()
  238. {
  239. int i=0;
  240. jump();
  241. ++i;
  242. jump();
  243. i+=3;
  244. jump();
  245. string ss="";
  246. for(;s[i]>='a'&&s[i]<='z';++i)
  247. ss+=s[i];
  248. int t=mp[ss];
  249. int *ii,u;//用指针引用值更加方便
  250. if(len[t]==1)
  251. ii=&a[t][0];
  252. else
  253. {
  254. ++i;
  255. u=getstring(i);
  256. ii=&a[t][u-st[t]];
  257. }
  258. while(s[i]==' '||s[i]==',')
  259. ++i;
  260. int from=getstring(i);
  261. while(s[i]==' '||s[i]==',')
  262. ++i;
  263. int to=getstring(i);
  264. int st=1,en=0,l=0;
  265. if(tot)
  266. st=tot;
  267. int br=1;
  268. while(1)
  269. {
  270. if(isend()&&br==1)//注意不要找到别人的右括号了 下同
  271. {
  272. if(tot)
  273. en=tot-2;//en是右括号上面一行相对st(1)的编号
  274. else
  275. en=l;
  276. break;
  277. }
  278. if(!strlen(s))//注意空串如果跳过会方便一些
  279. continue;
  280. ++l;
  281. i=0;
  282. jump();
  283. if(s[i]=='{')
  284. ++br;
  285. if(s[i]=='}')
  286. --br;
  287. if(!tot)
  288. {
  289. i=0;
  290. for(;s[i]!='\0';++i)
  291. F[l][i]=s[i];
  292. F[l][i]='\0';
  293. }
  294. }
  295. for(*ii=from;*ii<=to;++(*ii))
  296. {
  297. tot=st;
  298. while(tot<=en)
  299. {
  300. i=0;
  301. for(;F[tot][i]!='\0';++i)
  302. s[i]=F[tot][i];
  303. s[i]='\0';
  304. ++tot;
  305. qaq();
  306. }
  307. }
  308. tot=en+2;
  309. }
  310. void whi()
  311. {
  312. int i=0;
  313. char p[1000];
  314. for(;s[i]!='\0';++i)
  315. p[i]=s[i];
  316. p[i]='\0';
  317. int st=0,en=0,l=0;
  318. if(tot)//最外层不需要处理这里
  319. {
  320. st=tot-1;
  321. ++tot;
  322. }
  323. int br=1;
  324. while(1)
  325. {
  326. if(isend()&&br==1)
  327. {
  328. if(tot)
  329. en=tot-2;
  330. else
  331. en=l;
  332. break;
  333. }
  334. if(!strlen(s))
  335. continue;
  336. i=0;
  337. ++l;
  338. jump();
  339. if(s[i]=='{')
  340. ++br;
  341. if(s[i]=='}')
  342. --br;
  343. if(!tot)
  344. {
  345. i=0;
  346. for(;s[i]!='\0';++i)
  347. F[l][i]=s[i];
  348. F[l][i]='\0';
  349. }
  350. }
  351. while(1)
  352. {
  353. tot=st+1;
  354. i=0;
  355. for(;p[i]!='\0';++i)
  356. s[i]=p[i];
  357. s[i]='\0';
  358. if(!ihu(1))
  359. {
  360. tot=en+2;
  361. return;
  362. }
  363. while(tot<=en)
  364. {
  365. i=0;
  366. for(;F[tot][i]!='\0';++i)
  367. s[i]=F[tot][i];
  368. s[i]='\0';
  369. ++tot;
  370. qaq();
  371. }
  372. }
  373. }

洛谷 P3695 CYaRon!语 题解 【模拟】【字符串】的更多相关文章

  1. 洛谷P5020 货币系统 题解 模拟

    题目链接:https://www.luogu.org/problem/P5020 这道题目是一道模拟题,但是又有一点多重背包的思想在里面. 首先我们定义一个 vis[i] 来表示和为 i 的情况在之前 ...

  2. 洛谷P5019 铺设道路 题解 模拟/贪心基础题

    题目链接:https://www.luogu.org/problemnew/show/P5019 这道题目是一道模拟题,但是它有一点贪心的思想. 我们假设当前最大的深度是 \(d\) ,那么我们需要把 ...

  3. 洛谷 P5594 【XR-4】模拟赛

    洛谷 P5594 [XR-4]模拟赛 洛谷传送门 题目描述 X 校正在进行 CSP 前的校内集训. 一共有 nn 名 OIer 参与这次集训,教练为他们精心准备了 mm 套模拟赛题. 然而,每名 OI ...

  4. 洛谷P2832 行路难 分析+题解代码【玄学最短路】

    洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...

  5. 【洛谷P3960】列队题解

    [洛谷P3960]列队题解 题目链接 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n×m ...

  6. 洛谷P2312 解方程题解

    洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...

  7. 洛谷P1577 切绳子题解

    洛谷P1577 切绳子题解 题目描述 有N条绳子,它们的长度分别为Li.如果从它们中切割出K条长度相同的 绳子,这K条绳子每条最长能有多长?答案保留到小数点后2位(直接舍掉2为后的小数). 输入输出格 ...

  8. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  9. 洛谷 P1220 关路灯 题解

    Description 有 $n$ 盏路灯,每盏路灯有坐标(单位 $m$)和功率(单位 $J$).从第 $c$ 盏路灯开始,可以向左或向右关闭路灯.速度是 $1m/s$.求所有路灯的最少耗电.输入保证 ...

随机推荐

  1. Linux awk&sed

    awk AWK是强大的文本处理工具,擅长对日志文件迚行快速分析. 它丌仅用亍 Linux ,也是任何环境中现有的功能最强大的数据处理引擎之一. 名称得自亍它的发明者 Alfred Aho .Pet ...

  2. ZIP压缩格式与RAR压缩格式

    早已习惯了安装系统之后必须安装winrar,压缩文件也已经习惯了rar格式,这种习惯的力量真的挺可怕的.在工作中你的同事可能没有安装winrar,或者他们不喜欢安装盗版软件,这时候你给他们发送过去的是 ...

  3. Log4J 配置 详解

    Log4J的配置文件(Configuration File)就是用来设置记录器的级别.存放器和布局的,它可接key=value格式的设置或xml格式的设置信息.通过配置,可以创建出Log4J的运行环境 ...

  4. poj 1611 The Suspects(第一道并查集)

    题意: 有N个学生,编号为0-n-1,现在0号学生感染了非典,凡是和0在一个社团的人就会感染, 并且这些人如果还参加了别的社团,他所在的社团照样全部感染,社团个数为m,求感染的人数. 输入: n代表人 ...

  5. bootstrap列排序

    <!DOCTYPE html> <html> <head> <title>Bootstrap 实例 - 列排序</title> <li ...

  6. Reportng 的测试报告在 Jenkins 中显示不全

    通过Jenkins执行接口测试生成测试报告,用Jenkins的web服务打开html显示不全. 环境: Jenkins版本:1.651.2 Jenkins发布在mac上面 使用的是testng管理测试 ...

  7. LightOJ 1258 Making Huge Palindromes (Manacher)

    题意:给定上一个串,让你在后面添加一些字符,使得这个串成为一个回文串. 析:先用manacher算法进行处理如果发现有字符匹配超过最长的了,结束匹配,答案就是该字符前面那个长度加上该串原来的长度. 代 ...

  8. 图的遍历——BFS

    原创 裸一篇图的BFS遍历,直接来图: 简单介绍一下BFS遍历的过程: 以上图为例子,从0开始遍历,访问0,按大小顺序访问与0相邻的所有顶点,即先访问1,再访问2: 至此顶点0已经没有作用了,因为其本 ...

  9. CSS3的2D与3D转换

    2D和3D转换涉及到数学中的知识,作为一个数学专业的毕业生,不研究一下岂不是对不起自己的专业? 首先来看几个参数: 1.transform-origin:origin(起源,起点),也即变形的起点,在 ...

  10. angular启动过程

    第一步: .angular-cli.json 第二步: 第三步: 第四步: 第五步: