미션 세부 정보
C/C++ 언어를 사용하여 PL/0 컴파일러용 어휘 분석 프로그램을 작성하십시오. 참고 사항:
(1) 불법 문자 식별: @, &, ! 등
(2) 불법 단어 식별: 숫자와 숫자로 시작하는 문자의 조합;
(3) 식별자 및 부호 없는 정수의 길이는 8비트를 초과하지 않습니다.
(4) /* */ 및 // 형식의 주석 정보를 자동으로 인식하고 무시할 수 있습니다.
(5) 어휘 분석 중에 오류가 발생한 후 계속해서 오류 메시지를 식별하고 출력할 수 있습니다.
프로그래밍 요구 사항
위의 프로그래밍 작업을 완료한 후 오른쪽의 코드 편집기에 C/C++ 언어 소스 프로그램을 복사하여 붙여넣고 "평가" 버튼을 클릭하고 프로그램을 실행하면 시스템이 자동으로 결과를 비교합니다.
테스트 지침
플랫폼은 작성한 코드를 테스트합니다.
테스트 입력:
const a = 10;
var b, c;
procedure fun1;
if a <= 10 then
begin
c := b + a;
end;
begin
read(b);
while b # 0 do
begin
call fun1;
write(2 * c);
read(b);
end
end.
예상 출력:
(保留字,const)
(标识符,a)
(运算符,=)
(无符号整数,10)
(界符,;)
(保留字,var)
(标识符,b)
(界符,,)
(标识符,c)
(界符,;)
(保留字,procedure)
(标识符,fun1)
(界符,;)
(保留字,if)
(标识符,a)
(运算符,<=)
(无符号整数,10)
(保留字,then)
(保留字,begin)
(标识符,c)
(运算符,:=)
(标识符,b)
(运算符,+)
(标识符,a)
(界符,;)
(保留字,end)
(界符,;)
(保留字,begin)
(保留字,read)
(界符,()
(标识符,b)
(界符,))
(界符,;)
(保留字,while)
(标识符,b)
(运算符,#)
(无符号整数,0)
(保留字,do)
(保留字,begin)
(保留字,call)
(标识符,fun1)
(界符,;)
(保留字,write)
(界符,()
(无符号整数,2)
(运算符,*)
(标识符,c)
(界符,))
(界符,;)
(保留字,read)
(界符,()
(标识符,b)
(界符,))
(界符,;)
(保留字,end)
(保留字,end)
(界符,.)
테스트 입력:
const 2a = 123456789;
var b, c;
//单行注释
/*
* 多行注释
*/
procedure function1;
if 2a <= 10 then
begin
c := b + a;
end;
begin
read(b);
while b @ 0 do
begin
call function1;
write(2 * c);
read(b);
end
end.
예상 출력:
(保留字,const)
(非法字符(串),2a,行号:1)
(运算符,=)
(无符号整数越界,123456789,行号:1)
(界符,;)
(保留字,var)
(标识符,b)
(界符,,)
(标识符,c)
(界符,;)
(保留字,procedure)
(标识符长度超长,function1,行号:10)
(界符,;)
(保留字,if)
(非法字符(串),2a,行号:11)
(运算符,<=)
(无符号整数,10)
(保留字,then)
(保留字,begin)
(标识符,c)
(运算符,:=)
(标识符,b)
(运算符,+)
(标识符,a)
(界符,;)
(保留字,end)
(界符,;)
(保留字,begin)
(保留字,read)
(界符,()
(标识符,b)
(界符,))
(界符,;)
(保留字,while)
(标识符,b)
(非法字符(串),@,行号:17)
(无符号整数,0)
(保留字,do)
(保留字,begin)
(保留字,call)
(标识符长度超长,function1,行号:19)
(界符,;)
(保留字,write)
(界符,()
(无符号整数,2)
(运算符,*)
(标识符,c)
(界符,))
(界符,;)
(保留字,read)
(界符,()
(标识符,b)
(界符,))
(界符,;)
(保留字,end)
(保留字,end)
(界符,.)
문제 해결 아이디어
이중 포인터 + 지도
아이디어는 스크리닝과 식별의 두 단계로 나뉩니다.스크리닝은 문자열을 스캔 및 필터링하고 요구 사항을 충족하는 문자열을 추출하고 인식을 준비하는 것입니다.이 단계는 이중 포인터 알고리즘으로 실현할 수 있으며 인식은 문자열을 식별하는 것입니다. 추출된 문자열 . , 5개의 예약어, 연산자, 구분 기호, 부호 없는 정수 및 식별자 중 하나인지 확인합니다. 이 단계는 map 으로 식별 할 수 있습니다.
이중 포인터 알고리즘을 사용하여 문자열을 스캔하고 추출하는 과정에서 예약어, 연산자, 구분 기호, 부호없는 정수 및 식별자를 분류하고 식별하여 후속 분류 및 식별을 준비하십시오. 예약어, 부호 없는 정수, 식별자는 모두 숫자나 문자로 구성되어 있기 때문에 숫자나 문자로 구성된 문자열을 직접 스캔하여 필터링할 수 있으며, 구분 기호와 연산자는 별도로 스캔하여 필터링할 수 있습니다. 스캔이 문자열을 추출하면 이를 분류하고 식별할 수 있습니다. 마지막 댓글의 콘텐츠는 유효하지 않으며 인식할 필요가 없습니다.
코드
//识别保留字、运算符、标识符、界符、无符号整数 (可能还存在没有考虑的情况,仅供参考)
#include<bits/stdc++.h>
using namespace std;
map<string,int> B, Y; //B(保留字)、Y(运算符)
map<char,int> J, y; //J(界符)
string s;
int F; //(标记'/*''*/'注释)
int main()
{
B["const"]=B["var"]=B["procedure"]=B["begin"]=B["end"]=B["odd"]=B["if"]=B["then"]=B["call"]=B["while"]=B["do"]=B["read"]=B["write"]=1; //保留字,13个
Y["+"]=Y["-"]=Y["*"]=Y["/"]=Y["<"]=Y["<="]=Y[">"]=Y[">="]=Y["#"]=Y["="]=Y[":="]=1; //运算符,11个
y['+']=y['-']=y['*']=y['/']=y['<']=y['>']=y['=']=y['#']=y[':']=1;
J['(']=J[')']=J[',']=J[';']=J['.']=1; //界符,5个
string s1 = "//", s2 = "/*", s3 = "*/", str;
for(int id = 1; getline( cin, s); id++) {
int f = 0; // (标记'//'注释)
for(int i=0; s[i]!='\0'; i++) { //双指针算法(扫描识别)
while(s[i]!='\0' && (s[i]==' ' || s[i]=='\t')) i++; //去掉空格与'\t'
int f1 = 0, f2 = 0, f3 = 0, f4 = 0, flog = 0;
int j1 = i, j2 = i; //j1(保留字、标识符、无符号整数)、j2(运算符)
if(!((s[i]>='0'&&s[i]<='9') || (s[i]>='a'&&s[i]<='z') || (s[i]>='A'&&s[i]<='Z') || y[s[i]]==1 || J[s[i]]==1)) flog = 1; //标记非法字符
while(s[j1]!='\0' && ((s[j1]>='0'&&s[j1]<='9') || (s[j1]>='a'&&s[j1]<='z') || (s[j1]>='A'&&s[j1]<='Z')) ) {//识别数字与字母串
if( s[j1]>='0'&& s[j1]<='9' ) f1 = 1; //标记数字
else f2 = 1; //标记字母
j1 ++;
}
while(s[j2]!='\0' && y[ s[j2] ] == 1) f3 = 1, j2 ++; //识别运算符,并标记运算符
if(J[ s[i] ] == 1) f4 = 1; //识别界符,并标记界符
if(f1 || f2) str = s.substr( i, j1-i); //提取字符串
if(f1 == 1 && f2 == 0 && !f && !F) { //无符号整数
if(str.size() <= 8) cout<<"(无符号整数,"<<str<<")"<<endl;
else cout<<"(无符号整数越界,"<<str<<",行号:"<<id<<")"<<endl;
}
else if(f2 == 1 && B[str] != 1 && !f && !F) { //标识符
if(s[i]>='0' && s[i]<='9') cout<<"(非法字符(串),"<<str<<",行号:"<<id<<")"<<endl; //识别非法字符串
else if(str.size() <= 8) cout<<"(标识符,"<<str<<")"<<endl;
else cout<<"(标识符长度超长,"<<str<<",行号:"<<id<<")"<<endl;
}
else if(f2 == 1 && B[str] == 1 && !f && !F) cout<<"(保留字,"<<str<<")"<<endl; //保留字
else if( f3 == 1) { //运算符及注释
str = s.substr( i, j2-i); // 提取字符串
if(str == s1) f = 1; // '//'注释,标记'//'
else if(str == s2) F = 1; // '/*'注释,标记'/*'
else if(str == s3) F = 0; // '*/'注释,解除'/*/'标记
else if(!f && !F)
cout<<"(运算符,"<<str<<")"<<endl;
}
else if(f4 == 1 && !f && !F) //界符
cout<<"(界符,"<<s[i]<<")"<<endl;
else if(flog == 1 && !f && !F) cout<<"(非法字符(串),"<<s[i]<<",行号:"<<id<<")"<<endl; //识别非法字符
if(j1 != i) i = j1 - 1;
else if(j2 != i) i = j2 - 1;
}
}
return 0;
}