一、前提了解
设计词法分析程序,首先需要了解PL/0的单词的划分规则,根据所学内容。PL/0的单词可以划分为5个大类:保留字(关键字)、标识符、运算符、无符号整数和界符。具体的文法如下:
- 保留字:共有13个,包括 const , var , procedure , begin , end , odd , if , then , call , while , do , read , write。在使用到的时候将其按照字母的顺序进行排列,便于后续的二分查找。
文法:<保留字> ::= const | var | procedure | begin | end | odd | if | then | call | while | do | read | write
- 运算符:共有11个,包括4个整型算数运算符号 + 、 - 、 * 和 / ,6个比较运算符号 < 、 <= 、 > 、 >= 、 # 和 = ,1个赋值运算符 := 。由于/会和// /**/等注释的规则产生歧义,<=和>=这几个符号在判断的时候容易首先分开判断,所以这三个字符需要重点分析。
文法:<运算符> ::= + | - | * | / | < | <= | > | >= | # | = | :=
- 界符:共有5个,包括 ( 、 ) 、 , 、 ; 和 . 。
文法:<界符> ::= ( | ) | , | ; | .
- 无符号整数:是由一个或多个数字组成的序列,数字为 0 , 1 , 2 , … , 9 。
文法:<无符号整数>::=<数字>{<数字>}
- 标识符:是字母开头的字母数字序列,字母包括大小写英文字母: a , b , ..., z , A , B , …, Z 。
文法:<标识符> ::=<字母>{<字母>|<数字>}
所以我们从源文件中逐个读取字符,然后按照以上所划分的字符串类别对它们进行分类并输出,就可以实现一个简易的词法分析程序。
二、算法
DFA转换(即:利用一个个字符来组成独立的单词,运算符、标识符、保留字、无符号整数、界符之间相互隔开)
三、形式
1、输入形式:文件格式
2、存储形式:字符串数组形式
3、输出形式:二元式编码
四、结果展示
1、测试输入
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.
2、输出结果
五、思想
该程序思想是以fgets()内置函数来读取整个文件内容,其通过一行一行的读取文件中的内容,将一行字符串全部优化,消除每行前面的空白等优化操作,将符号与字母相隔,形式标识符、运算符、界符、无符号整数、保留字的单独单词形式(即:分析该行的单词类型)。
六、重要代码
以下代码是,分析每一行的单词类型:
//判断是否为保留字
char Is_bao(char num[],int n){
for(int i=0;i<13;i++){
int find = 0;
for(int k=0;k<strlen(a[i]);k++){
//printf("%c\n",a[i][k]==num[k]);
if(a[i][k]==num[k]){
find++;
//printf("-%d",find);
}else{
find = 0;
}
if(find==strlen(a[i])){
return '1';
break;
}
}
if(find==strlen(a[i])){
break;
}
}
return '0';
}
//判断是否为界符
char Is_jie(char num[],int n){
if(n==1&&(num[0]==';'||num[0]==','||num[0]==')'||num[0]=='('||num[0]=='.')){
return '1';
}
return '0';
}
//判断是否为运算符
char Is_yun(char num[],int n){
if(num[0]=='+'||num[0]=='<'||num[0]==':'||num[0]=='#'||num[0]=='>'||num[0]=='='||num[0]=='+'||num[0]=='*'){
return '1';
}
return '0';
}
//判断是否为无符号整数
char Is_num(char num[],int n){
if(num[0]>='0'&&num[0]<='9'){
int t=-1;
for(int i=0;i<n;i++){
if(num[i]<'0'||num[i]>'9'){
t=0;
break;
}
}
if(t==0){
return 'a';//非法字符(串)
}
int str_int = atoi(num);
if(str_int>255){
return 'b';
}
return '1';
}
return '0';
}
//综合判断
char Comprehensive(char num[],int n,int line_num){
int t=-1;
if(Is_bao(num,n)=='1'&&t==-1){
t=1;
printf("(保留字,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(")\n");
return '0';
}
if(Is_jie(num,n)=='1'&&t==-1){
t=1;
printf("(界符,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(")\n");
return '1';
}
if(Is_yun(num,n)=='1'&&t==-1){
t=1;
printf("(运算符,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(")\n");
return '2';
}
//printf("=======%c\n",Is_num(num,n));
if(Is_num(num,n)=='1'&&t==-1){
t=1;
printf("(无符号整数,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(")\n");
return '3';
}else if(Is_num(num,n)=='a'&&t==-1){
t=1;
printf("(非法字符(串),");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(",行号:%d",line_num);
printf(")\n");
return 'a';
}else if(Is_num(num,n)=='b'&&t==-1){
t=1;
printf("(无符号整数越界,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(",行号:%d",line_num);
printf(")\n");
return 'a';
}
if(n>=9){
t=1;
printf("(标识符长度超长,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(",行号:%d",line_num);
printf(")\n");
return 'a';
}
if(num[0]=='@'){
t=1;
printf("(非法字符(串),");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(",行号:%d",line_num);
printf(")\n");
return 'a';
}
t=1;
printf("(标识符,");
for(int j=0;j<n;j++){
printf("%c",num[j]);
}
printf(")\n");
return '4';
}
剩余代码若展示过于多,故不予展示。
需要私聊。