【洛谷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;
}