UVA12421 (Jiandan) Mua (I) - Lexical Analyzer 题解
闲话
蒟蒻的第一篇紫题题解!
2025-05-11 一年前过的题,今天一看被@
_s_z_y_ 给 hack 了,因此再来改一改这个题。
首先感谢@
_s_z_y_ 给出的 hack 数据:
s="\"\"".."\\\"\"'\\...'\\..".."\\\\".."114514"
另外注意到过了一年之后我代码中的 && 和 || 全变成了 and 和 or。
思路
直接模拟就是了,这个题码量并不算大。
输入
首先处理输入,这里我们用一个字符串数组来存储所有的输入,然后再进行处理。
while(getline(cin,sr))str[++cnt]=sr+'\n';
处理时需要双重循环,注意如果遍历到空格要跳过!(字符串内除外)
换行符在第一层循环末尾输出即可。
NUMBER
我们从最难处理的数字开始。
首先判断有没有 .,再判断是不是十六进制,然后再逐个往后筛,看看能否加进这个数字中,用一个字符串 \(ans\) 来储存答案,记得在最后清零!
bool checknum(int x,int y){
char ch=str[x][y];
if(ch>='0' and ch<='9' or ch=='e' or ch>='A' and ch<='F' or ch>='a' and ch<='f')return 1;
if(ch=='-' or ch=='+')if(str[x][y-1]=='e')return 1;else return 0;
if(ch=='.' and !pd){pd=1;return 1;}
return 0;
}
if(str[i][j]>='0' and str[i][j]<='9' or str[i][j]=='.' and str[i][j+1]>='0' and str[i][j+1]<='9'){
cout<<"[NUMBER] ";pd=0;
if(str[i][j]=='.')ans+=str[i][j],j++,pd=1;
if(str[i][j]=='0' and (str[i][j+1]=='X' or str[i][j+1]=='x'))ans+=str[i][j],ans+=str[i][j+1],j+=2,pd=1;
while(checknum(i,j))ans+=str[i][j],j++;j--;
cout<<ans<<'\n';
ans="";
}
STRING
接着我们再来看如何处理字符串。
如果碰到 ' 或 ",就将从这个字符往后筛直到找到另一个 ' 或 ",不过如果这个 ' 或 " 前一个字符是 \,则需跳过继续往后筛,同时需要注意如果字符串里出现连续多个 \ 的情况。
bool checkstring(int x,int y,char tmp){
char ch1=str[x][y],ch2=str[x][y-1];
if(tmp!=ch1)return 1;
else{if(ch2=='\\')return 1;else return 0;}
return 0;
}
if(str[i][j]=='\'' or str[i][j]=='\"'){
cout<<"[STRING] ";
ans+=str[i][j];
char tmp=str[i][j];j++;
while(checkstring(i,j,tmp))ans+=str[i][j],j++;
ans+=str[i][j];
cout<<ans<<'\n';
ans="";
}
SYMBOL
然后就是符号了。
直接用一个函数判断就行,但要注意先判断长度长的,避免重复。
int checksymbol(int x,int y){
char ch1=str[x][y],ch2=str[x][y+1];
if(ch1=='.' and ch2=='.' and str[x][y+2]=='.')return 3;
if(ch1=='.' and ch2=='.' or ch1=='=' and ch2=='=' or ch1=='>'
and ch2=='=' or ch1=='<' and ch2=='=' or ch1=='~' and ch2=='=')return 2;
/*+ - * / % ^ # == >= <= > < ~= ( ) { } [ ] ; : , . .. ... =*/
if(ch1=='.' or ch1==',' or ch1==':' or ch1==';' or ch1=='=' or ch1=='+' or ch1=='-' or ch1=='*'
or ch1=='/' or ch1=='%' or ch1=='^' or ch1=='#' or ch1=='<' or ch1=='>' or ch1=='(' or ch1==')'
or ch1=='{' or ch1=='}' or ch1=='[' or ch1==']')return 1;
return 0;
}
if(checksymbol(i,j)){
int tmp=checksymbol(i,j);
cout<<"[SYMBOL] ";
for(int k=0;k<tmp;k++)ans+=str[i][j+k];
j+=tmp,j--;
cout<<ans<<'\n';
ans="";
}
NAME and RESERVED
保留字可以在名称里判断。
先找到一个字母,然后往后滤,只要后一个字符是字母、数字、下划线中的一个就压入 \(ans\) 中,最后整体判断 \(ans\) 属不属于保留字即可。
bool checkname(int x,int y){
char ch=str[x][y];
if(ch>='0' and ch<='9' or ch>='a' and ch<='z'
or ch>='A' and ch<='Z' or ch=='_')return 1;
return 0;
}
bool checkreserved(string s){
for(int i=0;i<21;i++)if(s==RESERVED[i])return 1;
return 0;
}
if(str[i][j]>='a' and str[i][j]<='z' or str[i][j]>='A' and str[i][j]<='Z'){
while(checkname(i,j))ans+=str[i][j],j++;j--;
if(checkreserved(ans))cout<<"[RESERVED] "<<ans<<'\n';
else cout<<"[NAME] "<<ans<<'\n';
ans="";
}
COMMENT
只需要判断有没有两个连续的 _,然后把后面的全部刨去,注意要输出换行符!
if(str[i][j]=='-' and str[i][j+1]=='-')j=len-1;
完整代码
#include<bits/stdc++.h>
using namespace std;
string RESERVED[25]={"and","break","do","else","elseif","end","false","for","function","if","in","local","nil","not","or","repeat","return","then","true","until","while"};
string sr,str[1005],ans;
int cnt,len,j;
bool pd,flag;
bool checknum(int x,int y){
char ch=str[x][y];
if(ch>='0' and ch<='9' or ch=='e' or ch>='A' and ch<='F' or ch>='a' and ch<='f')return 1;
if(ch=='-' or ch=='+')if(str[x][y-1]=='e')return 1;else return 0;
if(ch=='.' and !pd){pd=1;return 1;}
return 0;
}
bool checkstring(int x,int y,char tmp){
char ch1=str[x][y],ch2=str[x][y-1];
if(tmp!=ch1)return 1;
else
if(ch2=='\\' and flag){
flag=0;
return 1;
}
else return 0;
return 0;
}
int checksymbol(int x,int y){
char ch1=str[x][y],ch2=str[x][y+1];
if(ch1=='.' and ch2=='.' and str[x][y+2]=='.')return 3;
if(ch1=='.' and ch2=='.' or ch1=='=' and ch2=='=' or ch1=='>'
and ch2=='=' or ch1=='<' and ch2=='=' or ch1=='~' and ch2=='=')return 2;
/*+ - * / % ^ # == >= <= > < ~= ( ) { } [ ] ; : , . .. ... =*/
if(ch1=='.' or ch1==',' or ch1==':' or ch1==';' or ch1=='=' or ch1=='+' or ch1=='-' or ch1=='*'
or ch1=='/' or ch1=='%' or ch1=='^' or ch1=='#' or ch1=='<' or ch1=='>' or ch1=='(' or ch1==')'
or ch1=='{' or ch1=='}' or ch1=='[' or ch1==']')return 1;
return 0;
}
bool checkname(int x,int y){
char ch=str[x][y];
if(ch>='0' and ch<='9' or ch>='a' and ch<='z'
or ch>='A' and ch<='Z' or ch=='_')return 1;
return 0;
}
bool checkreserved(string s){
for(int i=0;i<21;i++)if(s==RESERVED[i])return 1;
return 0;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
while(getline(cin,sr))str[++cnt]=sr+'\n';
for(int i=1;i<=cnt;i++){
ans="";
len=str[i].length();
for(int j=0;j<len;j++){
if(str[i][j]==' ')continue;
else if(str[i][j]=='-' and str[i][j+1]=='-')j=len-1;
else if(str[i][j]>='0' and str[i][j]<='9' or str[i][j]=='.' and str[i][j+1]>='0' and str[i][j+1]<='9'){
cout<<"[NUMBER] ";pd=0;
if(str[i][j]=='.')ans+=str[i][j],j++,pd=1;
if(str[i][j]=='0' and (str[i][j+1]=='X' or str[i][j+1]=='x'))ans+=str[i][j],ans+=str[i][j+1],j+=2,pd=1;
while(checknum(i,j))ans+=str[i][j],j++;j--;
cout<<ans<<'\n';
ans="";
}else if(str[i][j]=='\'' or str[i][j]=='\"'){
cout<<"[STRING] ";
ans+=str[i][j];
char tmp=str[i][j];j++;
flag=0;
while(checkstring(i,j,tmp)){
if(str[i][j]=='\\')flag=!flag;
ans+=str[i][j],j++;
}
ans+=str[i][j];
cout<<ans<<'\n';
ans="";
}else if(checksymbol(i,j)){
int tmp=checksymbol(i,j);
cout<<"[SYMBOL] ";
for(int k=0;k<tmp;k++)ans+=str[i][j+k];
j+=tmp,j--;
cout<<ans<<'\n';
ans="";
}else if(str[i][j]>='a' and str[i][j]<='z' or str[i][j]>='A' and str[i][j]<='Z'){
while(checkname(i,j))ans+=str[i][j],j++;j--;
if(checkreserved(ans))cout<<"[RESERVED] "<<ans<<'\n';
else cout<<"[NAME] "<<ans<<'\n';
ans="";
}
}
cout<<"[EOL]\n";
}
return 0;
}

浙公网安备 33010602011771号