实验一 词法分析
1.实验要求
(1)从源程序文件中读取有效字符流并将其分析识别单词符号,转换成二元组内部表示形
式输出。
(2)可视化方式展示词法分析识别过程或者词法分析器工作原理(选做)。
(3)实验时间 4 学时。
(4)实验完成后,要提交实验报告(包括源程序清单)。
2.实验内容
2.1 主程序设计考虑:
主程序的说明部分为各种表格和变量安排空间(关键字和特殊符号表)。
id 和 ci 数组分别存放标识符和常数;还有一些为造表填表设置的变量。
主程序的工作部分建议设计成便于调试的循环结构。每个循环处理一个单词;调用词法
分析过程;输出每个单词的内部码(种别编码,属性值)。建议从文件中读取要分析的符号
串。
2.2 词法分析过程考虑
该过程根据输入单词的第一个有效字符(有时还需读第二个字符),判断单词种别,产
生种别编码。对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表
中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组 id 中,将
常数存入数组中 ci 中,并记录其在表中的位置。
注:所有识别出的单词都用二元组表示。第一个表示单词的种别编码。例如:关键字
的 t=1;标识符的 t=2;常数 t=3;运算符 t=4;界符 t=5。第二个为该单词在各自表中的
指针或内部码值(常数表和标识符表是在编译过程中建立起来的。其 i 值是根据它们在源
程序中出现的顺序确定的)。
关键字和特殊符号如下(表中数字只是标记,不代表种别编码,种别编码自己定义):
编号 1
名字 int
编号 11
名字 printf
编号 21
名字 = =
编号 31
名字 (
2
char
12
return
22
>
32
)
3
float
13
main
23
<
33
{
4
void
14
read
24
!=
34
}
5
const
15
+
25
>=
35
;
7
6
else
if
16
17
– *
26
27
<= &&
36
37
,
“
8
do
18
/
28
||
38
‘
9
while
19
%
29
!
39
++
10
scanf
20
=
30
<>
40
--
将词法分析程序设计成独立一遍扫描源程序的结构。参考设计流程图如下:
图 1 词法分析程序流程图
源代码:#define _CRT_SECURE_NO_WARNINGS
#include"iostream"
#include
#include
using namespace std;
int i = 0;
char character[1000000];//字,扫描用
int constNum = 0;//常数的个数
int biaoshifuNum = 0; //标识符的个数
char key[32][20] = { "int","char","float","void","const","if",
"else","do","while","scanf","printf","return","main","read" };//关键字 t=1
char biaoshifubiao[100][30];//标识符 t=2
int consts[100];//常数 t=3
char operators[22][10] = { ":","++.","#",".","+","-","*","/","%","=","==",">",
"<","!=",">=","<=","&&","||","!","<>","++","--" };//运算符 t=4
//界符 t=5
char border[10][5] = { "(",")","{","}",";",",","[","]","\"","\'" };
//------------------------查找关键字
int Key(char c[])
{
for (i = 0; i < 15; i++)
{
if (strcmp(key[i], c) == 0)//如果查找成功,返回该关键字在关键字表中的位置
return i;
}
return -1;
}
//------------------------查找运算符
int YunSuanFu(char c[])
{
for (i = 0; i < 16; i++)
{
if (strcmp(operators[i], c) == 0)//如果查找成功,返回该运算符在运算符表中的位置
{
return i;
}
}
return -1;
}
//-------------------------查找界符
int JieFu(char c[])
{
for (i = 0; i < 10; i++)
{
if (strcmp(border[i], c) == 0)//如果查找成功,返回该界符在界符表中的位置
{
return i;
}
}
return -1;
}
//------------------------查找常数
int ChangShu(int c)
{
for (i = 0; i < constNum; i++)
{
if (consts[i] == c)//如果查找成功,返回该界符在界符表中的位置
{
return i;
}
}
return -1;
}
//------------------------查找标识符
int BiaoShiFu(char c[])
{
for (i = 0; i < biaoshifuNum; i++)
{
if (strcmp(biaoshifubiao[i], c) == 0)//如果查找成功,返回该界符在界符表中的位置
{
return i;
}
}
return -1;
}
//------------------------判断是不是关键字
bool IsKey(char c[])
{
for (i = 0; i < 16; i++)
{
if (strcmp(key[i], c) == 0)//如果查找成功,返回该运算符在运算符表中的位置
{
return true;
}
}
return false;
}
//------------------------判断是不是字母
bool IsLetter(char c)
{
if (c >= 'a'&&c <= 'z' || c >= 'A'&&c <= 'Z' || c == '_')
return true;
return false;
}
//------------------------判断是不是数字
bool Iscount(char c)
{
if (c >= '0'&&c <= '9')
return true;
return false;
}
//------------------------判断是不是界符
bool IsJieFu(char c)
{
if (c == '(' || c == ')' || c == '{' || c == '}' || c == ',' || c == ';' || c == '[' || c == ']' || c == '\'' || c == '\"')
return true;
return false;
}
//------------------------判断是不是运算符
bool IsYunSuanFu(char c)
{
//{"+","-","*","/","%","=","==",">","<","!=",">=","<=","&&","||","!","<>","++","--"};
if (c == ':' || c == '.' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%' || c == '=' || c == '!' || c == '>' || c == '<' || c ==
'&' || c == '#' || c == '|')
return true;
return false;
}
//------------------------预处理(去掉注释)
void YuChuLi(char c[], int n)
{
char NewCharacter[1000000];
int count = 0;
for (i = 0; i < n; i++)
{
if (c[i] == '/'&&c[i + 1] == '/')//---------说明遇到了单行注释
{
while (c[i] != '\n')//如果没有遇到回车,就继续向后扫描
i++;
}
if (c[i] == '/'&&c[i + 1] == '*')//说明遇到了多行注释
{
i = i + 2;
while (c[i] != '*'&&c[i + 1] != '/')
{
i++;
}
i = i + 2;
}
if (c[i] != '\n'&&c[i] != '\r')
{
NewCharacter[count++] = c[i];
}
}
NewCharacter[count] = '\0';
strcpy(c, NewCharacter);//得到与处理后的程序
}
int SaoMiao(char character[], int &p)//扫描程序
{
int id = 0;
char t[20];
int count = 0;
char c = character[p];
while (c == ' ')//跳过空格
{
p++;
c = character[p];
}
if (IsLetter(c))//如果单词开头为字母
{
t[count++] = character[p];
p++;
while (IsLetter(character[p]) || Iscount(character[p]))//如果单词后跟字母或数字
{
t[count++] = character[p];
p++;
}
t[count] = '\0';
if (Key(t) != -1)
{
cout << "(关键字,";
for (i = 0; i < count; i++)
cout << t[i];
cout << "," << Key(t) << ")";
cout << endl;
return p;
}
else //不是关键字,是标识符
{
cout << "(标识符,";
if (BiaoShiFu(t) == -1)//如果不在标识符表中,将其添加进去
{
for (i = 0; i < count; i++)
{
biaoshifubiao[biaoshifuNum][i] = t[i];
}
biaoshifuNum++;
for (i = 0; i < count; i++)
{
cout << t[i];
}
cout << "," << biaoshifuNum - 1 << ")";
cout << endl;
return p;
for (i = 0; i < count; i++)
cout << t[i];
cout << "," << BiaoShiFu(t) << ")";
cout << endl;
return p;
}
else
{
}
}
}
if (Iscount(character[p]))//如果首字符为数字
{
t[count++] = character[p];
p++;
while (Iscount(character[p]))//且后面还是数字
{
t[count++] = character[p];
p++;
}
t[count] = '\0';
int x = 0;
for (i = 0; i < count; i++)
{
x = x * 10 + (t[i] - '0');//字符串中数字变成 int
}
cout << "(常量,";
if (ChangShu(x) == -1)//如果不在常量表中,将其添加进去
{
consts[constNum++] = x;
cout << x;
cout << "," << constNum - 1 << ")";
cout << endl;
return p;
}
else
{
}
cout << x;
cout << "," << ChangShu(x) << ")";
cout << endl;
return p;
}
if (IsJieFu(character[p]))//如果为界符
{
t[count++] = character[p];
p++;
t[count] = '\0';
cout << "(界符,";
for (i = 0; i < count; i++)
cout << t[i];
cout << ",";
cout << JieFu(t) << ")";
cout << endl;
return p;
}
if (IsYunSuanFu(character[p]))//如果为运算符
{
t[count++] = character[p];
p++;
if (IsYunSuanFu(character[p]))
{