省选联考 2022,记忆犹新啊。
观察数据范围发现 $1 \leq n \leq 100$,递归展开可以逐层处理。
考虑模拟展开过程,每次发现一个标识符可展开则进行递归展开,在递归之前标记当前宏为展开状态,如果发现当前展开的宏已经处于展开状态则停止继续展开。
#include<bits/stdc++.h>
using namespace std;
ifstream fin("preprocessor.in");
ofstream fout("preprocessor.out");
unordered_map<string,string> ex;
unordered_map<string,bool> on;
int n;
void add(string s){
//#define XXXX
//01234567
int pos=8,lim=s.size()-1;
string nam,cont;
while(s[pos]!=' ') nam.push_back(s[pos]),++pos;
for(int i=pos+1;i<=lim;i++) cont.push_back(s[i]);
ex[nam]=cont;
}
void del(string s){
//#undef XXXX
//0123456
int lim=s.size()-1;
string nam;
for(int i=7;i<=lim;i++) nam.push_back(s[i]);
ex.erase(nam);
}
inline bool ischar(char x){
return isalpha(x)||isdigit(x)||x=='_';
}
string solution(string s){
int pos=0,lim=s.size()-1;
string ret;
while(pos<=lim){
if(ischar(s[pos])){
string x;
while(ischar(s[pos])){
x.push_back(s[pos]);
++pos;
}
if(ex.count(x)&&!on[x]){
string mem=x;
on[mem]=1;
x=solution(ex[x]);
on[mem]=0;
}
ret.append(x);
}
if(pos<=lim) ret.push_back(s[pos]),++pos;
}
return ret;
}
int main(){
string s;
fin>>n,getline(fin,s);
for(int i=1;i<=n;i++){
getline(fin,s);
if(s[0]=='#'){
if(s[1]=='d') add(s);
else del(s);
fout<<'\n';
}
else fout<<solution(s)<<'\n';
}
return 0;
}