词法分析
主函数
主程序首先输入你要分析的程序,调用cifa()函数,对输入的程序逐个进行分析
int main()
{
cout<<"请输入一段程序:"<<endl;
cin.getline(str,1000);
cout<<str<<endl;
eof = strlen(str);
while(forward<eof){
cifa();
};
char token[1024];
memset(token,0,sizeof(token));
copytoken(token);
install(token,flag);
}
全局变量
主要是懒得传递参数了,大伙可不要学我。。。
//词法中定义的全局变量:
//lex代表开始指针,forward代表向前指针,eof指的是结束的地方,都用int表示
int lexeme_beginning = 0,forward = 0,eof = 0;
//sum代表总共识别处理的符合个数,flag代表当前识别的符号类型
int sum = 0,flag = 0;
//charstack代表把识别出来的符号放入栈中
char charstack[1024][15];
//leixingma记录类型码
int leixingma[1024];
//str就是输入的字符串,代表缓冲序列
char str[Maxn];
额外方法(简单方法)
void install_id(char* token){
printf("标识符:");
sum++;
leixingma[sum-1] = 1;
cout<<token<<endl;
}
void install_num(char* token){
printf("数字:");
sum++;
leixingma[sum-1] = 2;
cout<<token<<endl;
}
void install_cha(char* token){
printf("运算符:");
sum++;
leixingma[sum-1] = 3;
cout<<token<<endl;
}
void install(char *token,int flag){
if(flag == 1)
return install_id(token);
if(flag == 2)
return install_num(token);
if(flag == 3)
return install_cha(token);
else
return ;
}
//从输入缓冲区读入一个字符放入ch
char getchar1(){
char ch;
if(forward == eof){
return ' ';
}
ch = str[forward];
++forward;
return ch;
}
//将向前指针回退一个字符,将ch置为空白符
void retract(int i,char ch){
forward -= i;
ch = ' ';
}
//将lex和forward之间的字符整出来!
char* copytoken(char *token){
//cout<<lexeme_beginning<<forward<<endl;
char st[1024];
memset(st,0,sizeof(st));
for(int i = 0;i<forward-lexeme_beginning;i++){ // 0 - 5
st[i] = str[lexeme_beginning+i];
}
lexeme_beginning = forward;
strcpy(token,st);
strcpy(charstack[sum],st);
return token;
}
//查看是digit还是alpha
int check(char ch){
if(isalpha(ch))
return 1;
if(isdigit(ch))
return 2;
return 0;
}
词法分析方法
原理:(韩老师上课的ppt)
不过只能识别图中这些符号,我还加上了{和}这两个符号,大伙也可以将#等符号添加进去识别,所以如果识别不了同学们想要的符号的话可以自行添加即可!
void cifa(){
char ch;
char token[1024];
memset(token,0,sizeof(token));
ch = getchar1();
if(ch ==' '||ch =='\t'||ch =='\n'){
//retract(1,ch);
copytoken(token);
install(token,flag);
flag = 0;
return ;
}
else if(isalpha(ch)&&(flag==0||flag==1)){
flag = 1;
return ;
}
else if(isalpha(ch)&&(flag==2||flag==3)){
retract(1,ch);
copytoken(token);
install(token,flag);
flag = 1;
return ;
}
else if(isdigit(ch)&&(flag == 1||flag == 2)){
flag = flag;
return ;
}
else if(isdigit(ch)&&(flag == 0)){
flag = 2;
return ;
}
else if(isdigit(ch)&&(flag==3)){
retract(1,ch);
copytoken(token);
install(token,flag);
flag = 2;
return ;
}else if(flag==2||flag==1){
retract(1,ch);
copytoken(token);
install(token,flag);
flag = 3;
return ;
}else if(flag == 3||flag == 0){
char ss[1024];
memset(ss,0,sizeof(ss));
switch(ch){
case '*':
ch = getchar1();
if(ch == '*'){
// s.push(ch);
strcpy(ss," EXP");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}
else{
retract(1,ch);
strcpy(ss," MULTI");
strcat(copytoken(token),ss);
//s.push(ch);
flag = check(ch);
return install_cha(token);
}
break;
case ':':
ch = getchar1();
if(ch == '='){
strcpy(ss," ASSIGN");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}
else{
retract(1,ch);
strcpy(ss," COLON");
strcat(copytoken(token),ss);
flag = check(ch);
return install_cha(token);
}
break;
case '<':
ch = getchar1();
if(ch == '='){
strcpy(ss," LE");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}
else if(ch == '>'){
strcpy(ss," NE");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}else{
retract(1,ch);
strcpy(ss," LT");
strcat(copytoken(token),ss);
flag = check(ch);
return install_cha(token);
}
break;
case '=':
strcpy(ss," EQ");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '>':
ch = getchar1();
if(ch == '='){
strcpy(ss," GE");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}else{
retract(1,ch);
strcpy(ss," GT");
strcat(copytoken(token),ss);
flag = check(ch);
return install_cha(token);
}
break;
case '+':
strcpy(ss," PLUS");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '-':
strcpy(ss," MINUS");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '/':
strcpy(ss," RDIV");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case ',':
//s.push(ch);
strcpy(ss," COMMA");
strcat(copytoken(token),ss);
return install_cha(token);
break;
case ';':
strcpy(ss," SEMIC");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '(':
strcpy(ss,"左括号");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case ')':
strcpy(ss,"右括号");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '{':
strcpy(ss,"左括弧");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '}':
strcpy(ss,"右括弧");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
default:
printf("error!,退出程序!");
exit(0);
}
return ;
}
}
总结
缺点:
1:C++较难识别’\n’这个符号,所以在输入程序的时候要将其‘一行化’
2:并没有实现对关键词的识别,即若有符号for,则其会将for看成一个标识符而不是关键词,这点需要根据你们的需要定义
3:肯定还有别的但我现在还没想到(控制台页面?)
还是建议用python写
测试
测试用例:
for(int i = 0 ;i <= n;i++) { a = b + c;}
完整程序(韩老师会不会查重?)
#include <bits/stdc++.h>
#include <ctype.h>
#include <string.h>
using namespace std;
#define Maxn 1024
//stack<char>s;
//测试用例:
//for(int i = 0 ;i <= n;i++) { a = b + c;}
//词法中定义的全局变量:
int lexeme_beginning = 0,forward = 0,eof = 0;
int sum = 0,flag = 0;
char charstack[1024][15];
int leixingma[1024];
char str[Maxn];
//语法中定义的全局变量:
int n = 0;
void install_id(char* token){
printf("标识符:");
sum++;
leixingma[sum-1] = 1;
cout<<token<<endl;
}
void install_num(char* token){
printf("数字:");
sum++;
leixingma[sum-1] = 2;
cout<<token<<endl;
}
void install_cha(char* token){
printf("运算符:");
sum++;
leixingma[sum-1] = 3;
cout<<token<<endl;
}
void install(char *token,int flag){
if(flag == 1)
return install_id(token);
if(flag == 2)
return install_num(token);
if(flag == 3)
return install_cha(token);
else
return ;
}
//从输入缓冲区读入一个字符放入ch
char getchar1(){
char ch;
if(forward == eof){
return ' ';
}
ch = str[forward];
++forward;
return ch;
}
//将向前指针回退一个字符,将ch置为空白符
void retract(int i,char ch){
forward -= i;
ch = ' ';
}
char* copytoken(char *token){
//cout<<lexeme_beginning<<forward<<endl;
char st[1024];
memset(st,0,sizeof(st));
for(int i = 0;i<forward-lexeme_beginning;i++){ // 0 - 5
st[i] = str[lexeme_beginning+i];
}
lexeme_beginning = forward;
strcpy(token,st);
strcpy(charstack[sum],st);
return token;
}
//( a + b ) * (d - c);
int check(char ch){
if(isalpha(ch))
return 1;
if(isdigit(ch))
return 2;
return 0;
}
void cifa(){
char ch;
char token[1024];
memset(token,0,sizeof(token));
ch = getchar1();
if(ch ==' '||ch =='/t'||ch =='/n'){
//retract(1,ch);
copytoken(token);
install(token,flag);
flag = 0;
return ;
}
else if(isalpha(ch)&&(flag==0||flag==1)){
flag = 1;
return ;
}
else if(isalpha(ch)&&(flag==2||flag==3)){
retract(1,ch);
copytoken(token);
install(token,flag);
flag = 1;
return ;
}
else if(isdigit(ch)&&(flag == 1||flag == 2)){
flag = flag;
return ;
}
else if(isdigit(ch)&&(flag == 0)){
flag = 2;
return ;
}
else if(isdigit(ch)&&(flag==3)){
retract(1,ch);
copytoken(token);
install(token,flag);
flag = 2;
return ;
}else if(flag==2||flag==1){
retract(1,ch);
copytoken(token);
install(token,flag);
flag = 3;
return ;
}else if(flag == 3||flag == 0){
char ss[1024];
memset(ss,0,sizeof(ss));
switch(ch){
case '*':
ch = getchar1();
if(ch == '*'){
// s.push(ch);
strcpy(ss," EXP");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}
else{
retract(1,ch);
strcpy(ss," MULTI");
strcat(copytoken(token),ss);
//s.push(ch);
flag = check(ch);
return install_cha(token);
}
break;
case ':':
ch = getchar1();
if(ch == '='){
strcpy(ss," ASSIGN");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}
else{
retract(1,ch);
strcpy(ss," COLON");
strcat(copytoken(token),ss);
flag = check(ch);
return install_cha(token);
}
break;
case '<':
ch = getchar1();
if(ch == '='){
strcpy(ss," LE");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}
else if(ch == '>'){
strcpy(ss," NE");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}else{
retract(1,ch);
strcpy(ss," LT");
strcat(copytoken(token),ss);
flag = check(ch);
return install_cha(token);
}
break;
case '=':
strcpy(ss," EQ");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '>':
ch = getchar1();
if(ch == '='){
strcpy(ss," GE");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
}else{
retract(1,ch);
strcpy(ss," GT");
strcat(copytoken(token),ss);
flag = check(ch);
return install_cha(token);
}
break;
case '+':
strcpy(ss," PLUS");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '-':
strcpy(ss," MINUS");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '/':
strcpy(ss," RDIV");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case ',':
//s.push(ch);
strcpy(ss," COMMA");
strcat(copytoken(token),ss);
return install_cha(token);
break;
case ';':
strcpy(ss," SEMIC");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '(':
strcpy(ss,"左括号");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case ')':
strcpy(ss,"右括号");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '{':
strcpy(ss,"左括弧");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
case '}':
strcpy(ss,"右括弧");
strcat(copytoken(token),ss);
flag = 0;
return install_cha(token);
break;
default:
printf("error!,退出程序!");
exit(0);
}
return ;
}
}
int main()
{
cout<<"请输入一段程序:"<<endl;
cin.getline(str,1000);
cout<<str<<endl;
eof = strlen(str);
while(forward<eof){
cifa();
};
char token[1024];
memset(token,0,sizeof(token));
copytoken(token);
install(token,flag);
}
后记
优化了一下代码,并使用QT搞了个简单的页面,需要的话可以联系邮箱