1、实验目的及要求
1.1、实验目的
加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。
1.2、实验要求
1)对单词的构词规则有明确的定义;
2)编写的分析程序能够正确识别源程序中的单词符号;
3)识别出的单词以<种别码,值>的形式保存在符号表中,正确设计和维护符号表;
4)对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析;
2、实验步骤
2.1、词法分析规则
<标识符>::=<字母>|<标识符><字母>|<标识符><数字>
<常数>::=<数字>|<数字序列><数字>
<数字序列>::=<数字序列><数字>|<数字>|<.>
<字母>::=a|b|c|……|x|y|z
<数字>::=0|1|2|3|4|5|6|7|8|9
<运算符>::=<关系运算符>|<算术运算符>|<逻辑运算符>|<位运算符>|<赋值运算符>
<算数运算符>::=+|-|*|/|...|--
<关系运算符>::=<|>|!=|>=|<=|==
<逻辑运算符>::=&&| || |!
<位运算符>::=&| | |!
<赋值运算符>::==|+=|-=|/=|*=
<分界符>::=,|;|(|)|{|}|:| // |/**/
<保留字>::=main|if|else|while|do|for|...|void
2.2、单词符号的编码
单词符号 | 种别码 | 单词符号 | 种别码 |
main | 0 | > | 26 |
if | 1 | >= | 27 |
else | 2 | < | 28 |
while | 3 | <= | 29 |
do | 4 | ! | 30 |
for | 5 | != | 31 |
switch | 6 | = | 32 |
case | 7 | == | 33 |
int | 8 | ( | 34 |
double | 9 | ) | 35 |
float | 10 | { | 36 |
long | 11 | } | 37 |
void | 12 | ; | 38 |
+ | 13 | : | 39 |
+= | 14 | | | 40 |
++ | 15 | || | 41 |
- | 16 | 数字 | 42 |
-= | 17 | 标识符 | 43 |
-- | 18 | , | 44 |
& | 19 | // | 45 |
&& | 20 | /**/ | 46 |
# | 21 | ||
* | 22 | ||
*= | 23 | ||
/ | 24 | ||
/= | 25 |
2.3、状态转换图
2.4、算法分析
①词法分析器工作的第一步是输入源程序文本。为了更好地对单词符号识别,把输入串预处理一下。预处理主要滤掉空格,跳过注释、换行符等。
②对预处理后的输入串依次扫描单个字符,使用if-while嵌套语句和switch case语句判断字符的类型,具体识别方法可看状态转换图。有时为了确定词性,需要超前扫描,若超前扫描的字符对识别当前单词无用处,则需要退还给输入串,以备识别下一单词字符时使用。
③若读入的字符与单词符号编码表的字符匹配不上,则报错,并输出出错行数。对识别处的单词符号以(单词符号,种别码)二元式的形式输出。
3、实验内容
3.1、流程图
3.2、程序的变量与函数说明
- input:全局字符数组,用来存放输入串
- word:全局字符数组,用来存放获取到的单词符号,限定长度为8
- ch:全局字符变量,用来存放最新读入的字符
- syn:全局整型变量,表示单词符号的编码
- p:全局整型变量,表示当前字符在input数组的位置
- m:全局整型变量,表示最新读入的字符在word数组的下标
- line:全局整型变量,当前行数
- keyword:全局字符数组,存放关键字
- init():获取输入串
- isKey():判断关键字的函数,若参数数组中是关键字,则把syn置为该关键字对应的编码并返回1,否则返回0
- isLetter():判断字母的函数,若参数字符是字母,则返回1,否则返回0
- isDigit():判断数字的函数,若参数字符是数字,则返回1,否则返回0
- isSpace():判断空白符的函数,若参数字符是空格、TAB或换行符,则返回1,否则返回0
- scaner():扫描输入串的函数,对读出的字符进行判断,若是单词符号表中的符号,则将syn置为对应的编码
3.3、源代码
#include <stdio.h>
#include <string.h>
char input[1000];//输入串
char word[8];//获取到的单词
char ch;
int syn;//种别码
int p;
int m;
int line;//行数
//关键字
char keyword[][8]={"main","if","else","while","do","for","switch","case","int","double","float","long","void"};
void scaner(void);
//获取输入串
void init()
{
int i=0;
printf("\n please input a string(end with '#'):\n");
do{
scanf("%c",&ch);
input[i++]=ch;
}while(ch!='#');
}
//判断是不是关键字
int isKey(char *str)
{
int n;
for(n=0;n<13;n++)
{
if(strcmp(str,keyword[n])==0)
{
syn=n;
return 1;
}
}
return 0;
}
//判断是不是数字
int isDigit(char c)
{
if (c>='0'&&c<='9')
return 1;
else
return 0;
}
//判断是不是字母
int isLetter(char c)
{
if ((c<='z'&&c>='a')||(c>='A'&&c<='Z'))
return 1;
else
return 0;
}
int isSpace(char c)
{
if (c==' '||c=='\t'||c=='\n')
{
return 1;
}
return 0;
}
void main()
{
init();//输入字符串
line=0;
p=0;
do{
scaner();
switch(syn)
{
case -1:
printf("you have input a wrong string in line %d\n",line);
break;
default:
printf("( %s,%d )\n",word,syn);
break;
}
}while(syn!=21);
}
void scaner(void)
{
//清空word
for(m=0;m<8;m++)
{
word[m] = ' ';
}
//读取字符
ch=input[p++];
m=0;
//当ch为空格或换行符时,继续往下读
while(isSpace(ch))
{
if (ch=='\n')
{
line++;
}
ch=input[p++];
}
//如果以字母开头
if(isLetter(ch))
{
//如果往后是字母或数字,把字符存入word中,然后往下继续读
//串长超过8则截断
while((isLetter(ch)||isDigit(ch))&&m<8)
{
word[m++]=ch;
ch=input[p++];
}
p--;
syn=43;
word[m++]='\0';
isKey(word);//判断是不是关键字
}
//如果是以数字开头,并且往后是数字
else if(isDigit(ch))
{
while((isDigit(ch)||ch=='.')&&m<8)
{
word[m++]=ch;
ch=input[p++];
}
//如果数字之后是字母 ,则出错
if (isLetter(ch))
{
while(!isSpace(ch))
{
ch=input[p++];
}
syn=-1;
return ;
}
p--;
syn=42;
}
else
{
switch(ch)
{
//比较运算符
case '<':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=29;
word[m++]=ch;
}
else
{
syn=28;
p--;
}
break;
case '>':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=27;
word[m++]=ch;
}
else
{
syn=26;
p--;
}
break;
case '!':
ch=input[p++];
if(ch=='=')
{
syn=31;
word[m++]=ch;
}
else
{
syn=30;
p--;
}
break;
case '=':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=33;
word[m++]=ch;
}
else
{
syn=32;
p--;
}
break;
//算术运算符+、-、*、/
case '+':
word[m++]=ch;
ch=input[p++];
if(ch=='+')
{
syn=15;
word[m++]=ch;
}
else if(ch=='=')
{
syn=14;
word[m++]=ch;
}
else
{
syn=13;
p--;
}
break;
case '-':
word[m++]=ch;
ch=input[p++];
if(ch=='-')
{
syn=18;
word[m++]=ch;
}
else if(ch=='=')
{
syn=17;
word[m++]=ch;
}
else if (isDigit(ch))
{
while(isDigit(ch))
{
word[m++]=ch;
ch=input[p++];
}
p--;
syn=42;
}
else
{
syn=16;
p--;
}
break;
case '*':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=23;
word[m++]=ch;
}
else
{
syn=22;
p--;
}
break;
case '/':
word[m++]=ch;
ch=input[p++];
if(ch=='=')
{
syn=25;
word[m++]=ch;
}
//如果是单行注释,则读到换行符为止
else if (ch=='/')
{
word[m++]=ch;
syn=45;
while (ch!='\n')
{
ch=input[p++];
}
line++;
}
//如果是多行注释,则读到匹配的*/为止
else if(ch=='*')
{
word[m++]=ch;
syn=46;
int flag=1;
while (flag)
{
ch=input[p++];
if (ch=='*')
{
if (input[p++]=='/')
{
word[m++]='*';
word[m++]='/';
flag=0;
}
else
{
p--;
}
}
if (ch=='\n')
{
line++;
}
}
}
else
{
syn=24;
p--;
}
break;
//界符
case '(':
syn=34;
word[m++]=ch;
break;
case ')':
syn=35;
word[m++]=ch;
break;
case '{':
syn=36;
word[m++]=ch;
break;
case '}':
syn=37;
word[m++]=ch;
break;
case ';':
syn=38;
word[m++]=ch;
break;
case '#':
syn=21;
word[m++]=ch;
break;
case ':':
syn=39;
word[m++]=ch;
break;
case ',':
syn=44;
word[m++]=ch;
break;
//逻辑运算符
case '&':
word[m++]=ch;
ch=input[p++];
if(ch=='&')
{
syn=20;
word[m++]=ch;
}
else
{
syn=19;
p--;
}
break;
case '|':
word[m++]=ch;
ch=input[p++];
if(ch=='|')
{
syn=41;
word[m++]=ch;
}
else
{
syn=40;
p--;
}
break;
default:
syn=-1;
break;
}
}
//字符串结束符
word[m++]='\0';
}
4、实验结果
因为printf和""不是单词符号表中的符号,因而判定输入有错
完整实验报告:词法分析器的设计与实现-C文档类资源-CSDN文库