UVA12421 (Jiandan) Mua (I) - Lexical Analyzer 题解

更好的阅读体验

题目传送门

闲话

蒟蒻的第一篇紫题题解!

2025-05-11 一年前过的题,今天一看被@
_s_z_y_
给 hack 了,因此再来改一改这个题。

首先感谢@
_s_z_y_
给出的 hack 数据:

s="\"\"".."\\\"\"'\\...'\\..".."\\\\".."114514"

另外注意到过了一年之后我代码中的 &&|| 全变成了 andor

思路

直接模拟就是了,这个题码量并不算大。

输入

首先处理输入,这里我们用一个字符串数组来存储所有的输入,然后再进行处理。

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;
}
posted @ 2024-02-23 20:49  MrSWdAxiv  阅读(37)  评论(0)    收藏  举报