PL/0语言词法分析
///
//
/
要求
输入PL/0语言源程序
输出二元式序列,(单词种类,单词的值)
准备工作
该语言的保留字,标识符以及数字可用一个状态机来识别,其余符号可用一个单独的状态机来识别。
正规式如下:
字母开头:letter(letter|digit)*
数字开头:digit(digit)*
符号省略
将正规式转换为DFA
程序流程图
开始写程序
首先,规定几个变量与函数。
- ch 字符,全局变量, 用来存放读入的字符
- strToken 字符数组, 全局变量,用来存放构成单词符号的字符串
- table表, 字符串数组,作为保留字表,存放保留字
- symbol表, 字符串数组,作为符号表
- GetChar()函数, 读取下一个字符到ch
- GetBC()函数, 跳过空格
- Concat()函数, 将ch中的字符连接到strToken
- Reserve()函数, 查找保留字表,strToken中现有字符串是否为保留字
- Isletter()函数 和 Isdigital()函数, 判断ch中的字符是字母还是数字
- RetChar()函数, 返回保留字对应编码
大体思想:在识别到一个完整的字母开头的单词后,查找保留字表,如果为保留字返回对应的编码,如果不是将该字符串识别为ident,整个源程序以 . 结尾,识别到.则结束程序,返回所有二元式序列。
设计思路因人而异,以上为本人设计思路,仅供参考。
代码
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
char ch; //全局变量ch,用来存放读入字符
char strToken[255]=""; //全局变量,用来存放构成单词符号的字符串
char table[13][10]={"begin","call",
"const","do","end","if",
"odd","procedure",
"read","then",
"var","while","write"}; //保留字表
char symbol[16][3]={"+","-","*",
"/","=","<>",
"<","<=",">",
">=",":=","(",
")",",",";","."}; //符号表
void GetChar(){
ch=getchar();
} //读入字符到ch
void GetBC(){
if(ch==' ')
GetChar();
} //跳过空白符
void Concat(){
strcat(strToken,&ch);
} //将ch中的字符连接到strToken
int Reserve(){
int index=-1;
int i;
for(i=0;i<14;i++)
{
if(strcmp(strToken,&table[i])==0)
{
index=i;
break;
}
}
if(index>=0)
return index;
else
return -1;
} //查找保留字表,strToken是否为保留字
bool Isletter(){
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
return true;
else
return false;
} //判断ch是否为字母
bool Isdigital(){
if(ch>='0'&&ch<='9')
return true;
else
return false;
} //判断ch是否为数字
char RetChar(int x,char a[]){
switch (x){
case 0:strcpy(a,"beginsym");break;
case 1:strcpy(a,"callsym");break;
case 2:strcpy(a,"constsym");break;
case 3:strcpy(a,"dosym");break;
case 4:strcpy(a,"endsym");break;
case 5:strcpy(a,"ifsym");break;
case 6:strcpy(a,"addsym");break;
case 7:strcpy(a,"proceduresym");break;
case 8:strcpy(a,"readsym");break;
case 9:strcpy(a,"thensym");break;
case 10:strcpy(a,"varsym");break;
case 11:strcpy(a,"whilesym");break;
case 12:strcpy(a,"writesym");break;
default:strcpy(a,"error");break;
}
} //返回保留字对应编码
void main() {
int code;
char word[20];
GetChar();
while(ch!='\0') {
strcpy(strToken,"");
GetBC();
if (Isletter()) { //状态1
Concat();
GetChar();
if (Isletter() || Isdigital()) { //状态3
Concat();
GetChar();
while (Isletter() || Isdigital()) {
Concat();
GetChar();
}
}
code = Reserve();
if (code != -1) {
RetChar(code,word);
} else
strcpy(word,"ident");
printf ("(%s,%s)\n",word, strToken);
} //字母开头识别
else if (Isdigital()) { //状态2
Concat();
GetChar();
if (Isdigital()) { //状态4
Concat();
GetChar();
while (Isdigital()) {
Concat();
GetChar();
}
strcpy(word,"number");
}
printf ("(%s,%s)\n",word, strToken);
} //数字开头
else if (ch=='\n')
{GetChar();} //换行符识别
else {
if (ch == '+') {
printf("(plus,+)\n");
GetChar();
} else if (ch == '-') {
GetChar();
printf("(minus,-)\n");
}
else if (ch == '*') {
GetChar();
printf("(times,*)\n");
}
else if (ch == '/') {
GetChar();
printf("(slash,/)\n");
}
else if (ch == '=') {
GetChar();
printf("(eql,=)\n");
}
else if (ch == '<') {
GetChar();
if (ch == '>') {
GetChar();
printf("(neq,<>)\n");
}
else if (ch == '=') {
GetChar();
printf("(leq,<=)\n");
}
else printf("(lss,<)\n");
} else if (ch == '>') {
GetChar();
if (ch == '=') {
GetChar();
printf("(geq,>=)\n");
}
else printf("(gtr,>)\n");
} else if (ch == ':') {
GetChar();
if (ch == '=') {GetChar();printf("(becomes,:=)\n");}
else printf("(error,:)\n");
} else if (ch == '(') {
GetChar();
printf("(lparen,()\n");
}
else if (ch == ')') {
GetChar();
printf("(rparen,))\n");
}
else if (ch == ',') {
GetChar();
printf("(comma,,)\n");
}
else if (ch == ';') {
GetChar();
printf("(semicolon,;)\n");
}
else if (ch == '.') {
GetChar();
printf("(period,.)\n");
}
} //符号与界符
} //主体循环
}
测试一下
输入:
const a=10;
var b,c;
begin
read(b);
c:=a+b;
write(c)
end.
测试结果: