问题描述:
用C或C++语言编写一个简单的词法分析程序,扫描C语言小子集的源程序,根据给定的词法规则,识别单词,填写相应的表。如果产生词法错误,则显示错误信息、位置,并试图从错误中恢复。简单的恢复方法是忽略该字符(或单词)重新开始扫描。
相关词法规则
<标识符>::=<字母>
<标识符>::=<标识符><字母>
<标识符>::=<标识符><数字>
<常量>::=<无符号整数>
<无符号整数>::=<数字序列>
<数字序列>::=<数字序列><数字>
<数字序列>::=<数字>
<字母>::=a|b|c|……|x|y|z
<数字>::=0|1|2|3|4|5|6|7|8|9
<加法运算符>::=+|-
<乘法运算符>::=*|/
<关系运算符>::=<|>|!=|>=|<=|==
<分界符>::=,|;|(|)|{|}
<保留字>::=main|int|if|else|while|do
编写词法分析程序的步骤:
(1)确定所要翻译的语言(或其子集)。
C语言
(2)设计属性字,及各类表格,如标识符表、常量表、符号及其机内表示对照表等。
与词法分析有关的表格:
1. 字符表
保留字:main,int,if,else,while,do
字母(全小写):a|b|c|……|x|y|z
数字:0,1,2,3,4,5,6,7,8,9
运算符和界符:<,>,!=,>=,<=,==,,,;,(,),{,}
2. 特定单词机内表示表
3.画出总控流程图及各个子程序的流程图。
4. 程序
输入:一个存放C语言程序的s.txt文件
输出:存放以(单词,种别码)形式输出的result.txt文件
需要6个数组:
1. 存储关键字 key[6]
2. 存储对应下标关键字的种别码 keyNum[6]
3. 存储运算符和界符 symbol[17]
4. 存储运算符对应下标的种别码 symbolNum[17]
5. 存储从文件中取出的每个字符(不包括括号)letter[1000]
主要函数:
TakeWord();
功能:将文件letter[]中每个字符进行提取,找出关键字,输出种别码
Num作为全局变量保存提取到字符的哪个下标
1. 先提取一个字符,如果是字母,进入case1,调用identifier(),不断的提取字母或数字进行连接,没连接一个字符用int isKeyWord()程序(返回关键字种别码)判断是否为关键字,是就退出函数返回string,不是就继续执行函数,直到连接的字符不再是字母或数字,即此时字符串为标识符
2. 如果是数字,进入case 2,调用Number()函数,不断进行字符串连接,知道下一个连接字符不再是数字
3. 如果是符号,进入case 3,调用symbolStr()函数,如果是=,>,<,!,则要继续进行下个字符判断,其余符号可以直接返回
其他辅助函数:
int isSymbol()判断运算符和界符,并返回种别码
bool isNum() 判断是否为数字
bool isLetter()判断是否为字母
int isKeyWord()判断是否为关键字,是返回种别码
int typeword()返回单个字符的类型
string identifier()标识符的连接
string symbolStr()符号和界符的连接
string Number()数字的连接
void print()输出
程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
//关键字
string key[6]={ "main" , "int" , "if" , "else" , "while" , "do" };
//关键字的种别码
int keyNum[6]={1,2,3,4,5,6};
//运算符和界符
string symbol[17]={ "<" , ">" , "!=" , ">=" , "<=" , "==" , "," , ";" , "(" , ")" , "{" , "}" , "+" , "-" , "*" , "/" , "=" };
//char symbol[12]={'<','>','!=','>=','<=','==',',',';','(',')','{','}'};
//运算符和界符的种别码
int symbolNum[17]={7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
//存放文件取出的字符
string letter[1000];
//将字符转换为单词
string words[1000];
int length; //保存程序中字符的数目
int num;
int isSymbol(string s){ //判断运算符和界符
int i;
for (i=0;i<17;i++){
if (s==symbol[i])
return symbolNum[i];
}
return 0;
}
//判断是否为数字
bool isNum(string s){
if (s>= "0" && s<= "9" )
return true ;
return false ;
}
//判断是否为字母
bool isLetter(string s)
{
if (s>= "a" && s<= "z" )
return true ;
return false ;
}
//判断是否为关键字,是返回种别码
int isKeyWord(string s){
int i;
for (i=0;i<6;i++){
if (s==key[i])
return keyNum[i];
}
return 0;
}
//返回单个字符的类型
int typeword(string str){
if (str>= "a" && str<= "z" ) // 字母
return 1;
if (str>= "0" && str<= "9" ) //数字
return 2;
if (str== ">" ||str== "=" ||str== "<" ||str== "!" ||str== "," ||str== ";" ||str== "(" ||str== ")" ||str== "{" ||str== "}"
||str== "+" ||str== "-" ||str== "*" ||str== "/" ) //判断运算符和界符
return 3;
}
string identifier(string s, int n){
int j=n+1;
int flag=1;
while (flag){
if (isNum(letter[j]) || isLetter(letter[j])){
s=(s+letter[j]).c_str();
if (isKeyWord(s)){
j++;
num=j;
return s;
}
j++;
}
else {
flag=0;
}
}
num=j;
return s;
}
string symbolStr(string s, int n){
int j=n+1;
string str=letter[j];
if (str== ">" ||str== "=" ||str== "<" ||str== "!" ) {
s=(s+letter[j]).c_str();
j++;
}
num=j;
return s;
}
string Number(string s, int n){
int j=n+1;
int flag=1;
while (flag){
if (isNum(letter[j])){
s=(s+letter[j]).c_str();
j++;
}
else {
flag=0;
}
}
num=j;
return s;
}
void print(string s, int n){
cout<< "(" <<s<< "," <<n<< ")" <<endl;
}
void TakeWord(){ //取单词
int k;
for (num=0;num<length;){
string str1,str;
str=letter[num];
k=typeword(str);
switch (k){
case 1:
{
str1=identifier(str,num);
if (isKeyWord(str1))
print(str1,isKeyWord(str1));
else
print(str1,0);
break ;
}
case 2:
{
str1=Number(str,num);
print(str1,24);
break ;
}
case 3:
{
str1=symbolStr(str,num);
print(str1,isSymbol(str1));
break ;
}
}
}
}
int main(){
char w;
int i,j;
freopen ( "s.txt" , "r" ,stdin);
freopen ( "result.txt" , "w" ,stdout); //从控制台输出,而不是文本输出
length=0;
while (cin>>w){
if (w!= ' ' ){
letter[length]=w;
length++;
} //去掉程序中的空格
}
TakeWord();
// for(j=0;j<length;j++){
// cout<<letter[j]<<endl;
// }
fclose (stdin); //关闭文件
fclose (stdout); //关闭文件
return 0;
}
|
运行结果:
s.txt
Result.txt
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/Naux1/article/details/78196465