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;elsereturn 0;
}
//判断是不是字母
int isLetter(char c)
{if ((c<='z'&&c>='a')||(c>='A'&&c<='Z'))return 1;elsereturn 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文库