一.要求
1.1 待分析的简单词法
(1)关键字:所有的关键字都是小写
begin if then while do end
(2)运算符和界符
:= + - * / < <= <> > >= = ; ( ) $
(3)其他单词是标识符(ID)和整型常数(NUM),通过以下正规式定义:
ID = letter (letter | digit)*
NUM = digit digit*
(4)空格有空白、制表符和换行符组成。空格一般用来分隔ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
1.2 各种单词符号对应的编码(类别):
表1 各种单词符号对应的编码
单词符号 | 编码 | 单词符号 | 编码 |
begin | 1 | := | 17 |
if | 2 | < | 18 |
then | 3 | <> | 20 |
while | 4 | <= | 21 |
do | 5 | > | 22 |
end | 6 | >= | 23 |
letter(letter|digit)* | 10 | = | 24 |
digit digit* | 11 | ; | 25 |
+ | 13 | ( | 26 |
- | 14 | ) | 27 |
* | 15 | $ | 0 |
/ | 16 |
|
|
1.3 词法分析程序的功能:
输入:所给文法的源程序字符串。
输出:二元组(编码,值)构成的序列。
其中:syn为单词种别码;
token为存放的单词自身字符串;
num为整型常数。
例如:对源程序beginx:=9; if x>9 then x:=2*x+1/3; end $的源文件,经过词法分析后输出如下序列:
(1,begin) (10,x)(17,:=) (11,9) (25,;) (2,if)……
二.具体算法
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
2.1 主程序示意图:
主程序示意图如图3-1所示。其中初始包括以下两个方面:
⑴ 关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下:
char *keywords[6] = {
"begin","if","then","while","do","end"
};
(2)程序中需要用到的主要变量为syn,token和num
3.2 扫描子程序的算法思想:
首先设置3个变量:①token用来存放构成单词符号的字符串;②num用来放整型单词;③syn用来存放单词符号的种别码。扫描子程序主要部分流程如图3-2所示。
三.源代码
#include<stdio.h>
#include<string.h>
int syn;
char token[10];
int num,i = 0;
char sentence[1000];
char *keywords[6] = {
"begin","if","then","while","do","end"
};
void handle() {
int j = 0;
char ch = sentence[i++];
syn = -1;
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
//处理letter(letter|digit)*这一类(如果是关键字下面处理)
while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')) {
token[j++] = ch;
ch = sentence[i++];
}
token[j] = '\0';
i--;
syn = 10;
//关键字处理
for(int k = 0;k < 6;k++) {
if(strcmp(token,keywords[k]) == 0) {
syn = k+1;
break;
}
}
} else {
//处理digit digit*这一类
if (ch >= '0' && ch <= '9') {
num = 0;
while(ch >= '0' && ch <= '9') {
num = num*10 + ch - '0';
ch = sentence[i++];
}
i--;
syn = 11;
}
else {
//处理<开头的一类
if(ch == '<') {
token[j++] = ch;
ch = sentence[i++];
if(ch == '>') {
syn = 20;
token[j++] = '>';
token[j] = '\0';
} else {
if(ch == '=') {
syn = 21;
token[j++] = '=';
token[j] = '\0';
} else {
syn = 18;
token[j] = '\0';
i--;
}
}
} else {
//处理>开头的一类
if(ch == '>') {
token[j++] = ch;
ch = sentence[i++];
if(ch == '=') {
syn = 23;
token[j++] = '=';
token[j] = '\0';
} else {
syn = 22;
token[j] = '\0';
i--;
}
} else {
//一些单个字符的处理(:=特殊点)
switch(ch) {
case '+': syn = 13;token[j++] = '+';token[j] = '\0';break;
case '-': syn = 14;token[j++] = '-';token[j] = '\0';break;
case '*': syn = 15;token[j++] = '*';token[j] = '\0';break;
case '/': syn = 16;token[j++] = '/';token[j] = '\0';break;
case ':': syn = 17;token[j++] = ':';token[j++] = '=';token[j] = '\0';i++;break;
case '=': syn = 24;token[j++] = '=';token[j] = '\0';break;
case ';': syn = 25;token[j++] = ';';token[j] = '\0';break;
case '(': syn = 26;token[j++] = '(';token[j] = '\0';break;
case ')': syn = 27;token[j++] = ')';token[j] = '\0';break;
case '$': syn = 0;token[j++] = '$';token[j] = '\0';break;
}
}
}
}
}
}
int main() {
printf("Please Input:\n");
int i = 0;
char ch;
//读入
do {
ch = getchar();
sentence[i++] = ch;
} while(ch != '$');
//一个个处理,直到结束
do {
handle();
if (syn == -1) {
continue;
}
if (syn == 11) {
printf("(%d,%d)\n",syn,num);
} else {
printf("(%d,%s)\n",syn,token);
}
} while(syn);
}
四.程序运行结果