一个简单的词法分析器
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。其中,
syn为单词种别码。
Token为存放的单词自身字符串。
Sum为整型常量。
具体实现时,可以将单词的二元组用结构进行处理。
1)关键字
main if then while do static int double struct break else
long switch case typedef char return const float short
continue for void default sizeof do
所有的关键字都是小写。
2)运算符和界符
+ - * / : := < <> <= > >= = ; ( ) #
3)其他标记ID和NUM
通过以下正规式定义其他标记:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…
4)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。
4、各种单词符号对应的种别码
表1 各种单词符号的种别码
单词符号 种别码 单词符号 种别码
main 1 ; 41
if 2 ( 42
then 3 ) 43
while 4 int 7
do 5 double 8
static 6 struct 9
ID 25 break 10
NUM 26 else 11
+ 27 long 12
- 28 switch 13
* 29 case 14
/ 30 typedef 15
: 31 char 16
:= 32 return 17
< 33 const 18
<> 34 float 19
<= 35 short 20
> 36 continue 21
>= 37 for 22
= 38 void 23
default 39 sizeof 24
do 40 # 0
```cpp
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
//存放处理后的字符串
char tempstr[255]= {};
//空格标志
bool temp=false;
//临时数组
char word[255]= {};
//keyword关键字
string Keyword[26]= {
"main","if","then","while","do",
"static","defualt","do","int","double",
"struct","break","else","long","swtich",
"case","typedf","char","return","const",
"float","short","continue","for","void",
"sizeof"
};
char Symbol2[12]= {'+','-','*','/','=',';','(',')','#',':','<','>'};
int IsSymbol2(char ch) {
for(int i=0; i<12; i++) {
if(ch==Symbol2[i])
return 1;
}
return -1;
}
int Keyword_num[26]= {1,2,3,4,5,6,39,40,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
//运算符,定界符等
char Symbol[9]= {'+','-','*','/','=',';','(',')','#'};
//对应的种码值
int Symbol_num[9]= {27,28,29,30,38,41,42,43,0};
//判断是否为字母
bool IsChar(char ch) {
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
return true;
return false;
}
//判断是否为数字
bool IsDigit(char ch) {
if(ch>='0'&&ch<='9')
return true;
return false;
}
//判断是否为定界符等
int IsSymbol(char ch) {
for(int i=0; i<9; i++) {
if(ch==Symbol[i])
return i;
}
return -1;
}
//判断是否为关键字
int IsKeyword(string str) {
for(int i=0; i<26; i++) {
if(str==Keyword[i]) {
return i;
}
}
//不是关键字即为ID
return 25;
}
//空格处理
void Space(char a[]) {
int j=0;
memset(word,0,255);//清空上次残留
temp=false;
for(int i=0; i<strlen(a); i++) {
if(a[i]!=' ' && a[i]!='\t') {
word[j++]=a[i];
temp=false;
} else {
if(!temp&&a[i]!='\t') {
word[j++]=a[i];
temp=true;
}
}
}
}
//处理"//"注释
void prePro() {
int j=0;
memset(tempstr,0,255);
for(int i=0; i<strlen(word); i++) {
if(word[i]=='/'&&word[i+1]=='/') {
while(i<strlen(word)) {
i++;
}
} else {
tempstr[j++]=word[i];
}
}
}
int main() {
char instr[255]= {}; //接收输入字符串
bool flag=false; //多行注释标志,false为未处于注释区域
string Token; //存放字符串
char *str=NULL; //存放每行的字符串
char delims[]=" "; //分割标志
//freopen("词法分析器测试.cpp","r",stdin);
//freopen("result.txt","w",stdout);
while((gets(instr))!=NULL) {
Space(instr);
// for(int i=0; i<strlen(word); i++)
// printf("%c",word[i]);
// printf("\n");
prePro();
// for(int i=0; i<strlen(tempstr); i++)
// printf("%c",tempstr[i]);
// printf("\n");
str=strtok(tempstr,delims);//分割字符串
while(str!=NULL) {
for(int i=0; i<strlen(str); i++) {
if(*(str+i)=='/') {
if(*(str+i+1)=='*') {
flag=true;
}
}
//注释处理: */,注释区域结束
if(*(str+i)=='*'&&flag) {
if(*(str+i+1)=='/') {
flag=false;
i=i+2;
}
}
//头文件,宏定义
// if(*(str)=='#'&&(!flag)) {
// }
//以"_"开头的违法标识符
if(*(str+i)=='_'&&(!flag)) {
while(IsChar(*(str+i))||IsDigit(*(str+i))||*(str+i)=='_') {
Token+=*(str+i);
i++;
}
printf("<违法标识符,%s>\n",Token.c_str());
Token="";
}
//标识符,关键词
if(IsChar(*(str+i))&&(!flag)) {
//printf("进入标识符判断\n");
while(IsChar(*(str+i))||IsDigit(*(str+i))||*(str+i)=='_') {
Token+=*(str+i);
i++;
}
if(IsKeyword(Token)!=25) {
printf("<%d,%s>\n",Keyword_num[IsKeyword(Token)],Token.c_str());
} else printf("<25,%s>\n",Token.c_str());
Token="";
//printf("结束标识符判断\n");
}
if(IsDigit(*(str+i))&&(!flag)) {
//printf("进入数字判断\n");
while(IsDigit(*(str+i))) {
Token+=*(str+i);
//此处可以使用atoi(Token) 将Token转化为Sum整型常量
i++;
}
//数字开头的违法标识符
if((IsSymbol2(*(str+i))==-1)&&i<strlen(str)) {
while(IsChar(*(str+i))||IsDigit(*(str+i))||*(str+i)=='_') {
Token+=*(str+i);
i++;
}
printf("<违法标识符,%s>\n",Token.c_str());
} else {
int number = atoi(Token.c_str());
//二进制输出
int b[32];int k;int a=0;int z=0;
while(number!=0){
k=number%2;
b[a++]=k;
number=number/2;
z++;
}
printf("<26,");
for(int i=z-1;i>=0;i--)
printf("%d",b[i]);
printf(">\n",b[i]);
}
Token="";
}
//<,<=,<>判断
if(*(str+i)=='<'&&(!flag)) {
if(*(str+i+1)=='=') {
printf("<35,<=>\n");
i++;
}
else if(*(str+i+1)=='>') {
printf("<34,<>>\n");
i++;
} else printf("<33,<>\n");
}
//>,>=判断
else if(*(str+i)=='>'&&(!flag)) {
if(*(str+i+1)=='=') {
printf("<37,>>\n");
} else printf("<36,>>\n");
}
//:,:=判断
else if(*(str+i)==':'&&(!flag)) {
if(*(str+i+1)=='=') {
printf("<32,:=>\n");
i++;
} else printf("<31,:>\n");
} else if(*(str+i)=='/'&&(!flag)&&*(str+i+1)=='*') {
flag=true;
} else if(*(str+i)=='*'&&*(str+i+1)=='/'&&flag) {
flag=false;
i=i+2;
}
//定界符等判断
else if(IsSymbol(*(str+i))!=-1&&(!flag)) {
printf("<%d,%c>\n",Symbol_num[IsSymbol(*(str+i))],*(str+i));
}
}
str=strtok(NULL,delims);
}
}
return 0;
system("pause");
}