理解词法分析的功能,熟悉词法分析程序的构造。
利用状态转换图来确定程序的流程。
定义一个单词集,能用状态转换图描述。测试应满足分支覆盖。
配置有C/C++开发环境的计算机设备。
如果一个种别只含有一个单词符号,则内码值为-1;如果一个种别含有多个单词符号(如:标识符、常数),用它自身的值作为内码值。
定义一个结构体数组Result,用它存放识别出的单词符号的种别编码及内码值。如:输入k=99; 则输出为:(100, k), (13, -1), (110, 99), (18, -1), (0,)
// -*- coding: utf-8 -*-
// @ Date : 2020/5/20 13:14
// @ Author : RichardLau_Cx
// @ file : Richard.cpp
// @ IDE : Dex-C++
// @ Source : 编译原理实验
/**
* 1. 以学习他人的经验为主,带入自己的想法为辅
* 2. 频繁debug各函数实现,是一种变相的效率提升
* 3. 由于很多变量都是公共变量,所以函数调用时则不必传值
*/
#include
#include
#include
using namespace std;
const char KW[6][10] = {"if", "else", "while", "int", "float", "char"}; // 保留字存储:以保留字为行,以保留字的每个字母为列
char inputString[99];
int number=0; // 各单词结构体数组的索引,相当于统计单词个数
int i=0; // 字符串匹配位置
int k=0; // k为单词的内码值下标
//(1)定义语言子集的单词符号的种别编码及内码值
// 定义结构体数组Result
typedef struct{
int typeNumber; // 单词符号的种别编码
char code[100]; // 内码值
// string code;
} Word; // 单词类型定义
Word Result[100];
void words();
void keyWord();
void state0();
void state1();
void state2();
void state3();
void state4();
void state5();
void state6();
void state7();
void state8();
void state9();
void state10();
void state11();
void state12();
void state13();
void state14();
void state15();
void state16();
void state17();
void state18();
void state19();
void state20();
void state21();
void output();
void error();
void end();
/*
当前进度:
1. 完成state0()和state1()的功能实现
*/
void words()
{
/*
若传字符串,则考虑使用指针
*/
cout << "function: words(): " << endl << "input: ";
gets(inputString);
// cin >> inputString; // 此方法拿不到字符串中的空格
while (inputString[i] != '\0')
{
k = 0; // k为单词的内码值下标,即Result[number].Code[k]
while (inputString[i] == ' ') i++; // 剔除空格
state0(); // 从0状态出发,直至到达一个终态,就识别出一个单词
// 若识别出的是标识符,则需要进一步判断是否为保留字
if (Result[number].typeNumber == 100)
{ // 如果单词为标识符,再进行判断是不是保留字
keyWord();
}
// 输出当前(最后一个)单词
// cout << "number: " << number << "\t typeNumber: " << Result[number].typeNumber << "\t Result[number].code: " << Result[number].code << endl;
i++; // 从输入串中读出下一个字符
number++; // 全局变量,统计单词个数
}
// gets(string)
}
void keyWord()
{
int i;
// cout << "function: keyWord()" << endl;
for (i=0; i < 6; i++)
{ // 目前共有6个保留字
if (strcmp(Result[number].code, KW[i]) == 0)
{ // 将标识符与保留字进行比较
Result[number].typeNumber = i+1; // 种别编码刚好是保留字下标+1
strcpy(Result[number].code, "-1");
break;
}
}
}
//(3)状态转换图的实现
void state0()
{ // 初态函数
if ((inputString[i] >= 'a' && inputString[i] <= 'z') || (inputString[i] >= 'A' && inputString[i] <= 'Z'))
{ // 判断当前输入的字符是否为;字母
Result[number].code[k] = inputString[i]; // 把当前输入字符串,加入到返回结果的二元组的内码值当中
i++; // 读取下一个输入字符 -输入
k++; // 内码值位置加1 -存储
state1(); // 转到状态1
}
else if (inputString[i] == '+')
{ // 如果当前输入字符串为 '+'
strcpy(Result[number].code, "-1"); // '+'的内码值为-1
i++;
state2();
}
else if (inputString[i] == '>')
{
strcpy(Result[number].code, "-1");
i++;
state3();
}
else if (inputString[i] == '=')
{
strcpy(Result[number].code, "-1");
i++;
state4();
}
else if (inputString[i] == '*')
{
strcpy(Result[number].code, "-1");
i++;
state5();
}
else if (inputString[i] == ',')
{
strcpy(Result[number].code, "-1");
state6();
}
else if (inputString[i] == ';')
{
strcpy(Result[number].code, "-1");
state7();
}
else if (inputString[i] == '(')
{
strcpy(Result[number].code, "-1");
state8();
}
else if (inputString[i] == ')')
{
strcpy(Result[number].code, "-1");
state9();
}
else if (inputString[i] == '-')
{
strcpy(Result[number].code, "-1");
state10();
}
else if (inputString[i] == '/')
{
strcpy(Result[number].code, "-1");
state11();
}
else if (inputString[i] == '{')
{
strcpy(Result[number].code, "-1");
state12();
}
else if (inputString[i] == '}')
{
strcpy(Result[number].code, "-1");
state13();
}
else if (inputString[i] == '<')
{
strcpy(Result[number].code, "-1");
i++;
state14();
}
else if (inputString[i] == '!')
{
strcpy(Result[number].code, "-1");
i++;
state15();
}
else if (inputString[i] >= '0' && inputString[i] <= '9')
{
Result[number].code[k] = inputString[i]; // 把当前输入字符,加入到返回结果的二元组的内码值中
i++;
k++;
state16();
}
else
{ // 若输入非法字符
error();
}
}
void state1()
{ // 由于1状态含有回路,则对于包含回路的状态,通过while语句来实现
while ((inputString[i] >= 'a' && inputString[i] <= 'z') || (inputString[i] >= 'A' && inputString[i] <= 'Z') || (inputString[i] >= '0' && inputString[i] <= '9'))
{ // 若继续为字母或者数字(首字符不能为数字)
Result[number].code[k] = inputString[i]; // 把当前输入字符继续存入到内码值中
i++;
k++;
}
Result[number].typeNumber = 100; // 标识符:种类编号为100
Result[number].code[k] = '\0'; // 给当前内码值的末端加上结束符
i--; // 由于读出其他字符才能到达终态,故多了一个字符,则需将当前读入的字符回退
}
void state2()
{
if (inputString[i] == '+') // 当前输入字符串为'+'号时
{
Result[number].typeNumber=8; // 识别出'++', 种别为8
}
else if (inputString[i] == '=')
{
Result[number].typeNumber=9; // 识别出'+=', 种别为9
}
else
{ // 当前输入字符为其他字符时
Result[number].typeNumber=7; // 识别出单个'+',种别为7
i--; // 由于读出其他字符,所以当前读入字符需回退
}
}
void state3()
{
if (inputString[i] == '=')
{
Result[number].typeNumber=11; // 识别出'>=',种别为11
}
else if (inputString[i] == '>')
{
Result[number].typeNumber=12; // 识别出'>>',种别为12
}
else
{
Result[number].typeNumber=10; // 识别出单个'>',种别为10
i--;
}
}
void state4()
{
if (inputString[i] == '=')
{
Result[number].typeNumber=14; // 识别出'==', 种别为14
}
else
{
Result[number].typeNumber=13; // 识别出单个'=',种别为13
i--;
}
}
void state5()
{
if (inputString[i] == '*')
{
Result[number].typeNumber=16; // 识别出'**',种别为16
}
else
{
Result[number].typeNumber=15; // 识别出单个'*',种别为15
i--;
}
}
void state6()
{
Result[number].typeNumber=17; // 单个',',种别为17
}
void state7()
{
Result[number].typeNumber=18; // 单个';',种别为18
}
void state8()
{
Result[number].typeNumber=19; // 单个'(',种别为19
}
void state9()
{
Result[number].typeNumber=20; // 单个')',种别为20
}
void state10()
{
Result[number].typeNumber=21; // 单个'-',种别为21
}
void state11()
{
Result[number].typeNumber=22; // 单个'/',种别为22
}
void state12()
{
Result[number].typeNumber=23; // 单个'{',种别为23
}
void state13()
{
Result[number].typeNumber=24; // 单个'}',种别为24
}
void state14()
{
if (inputString[i] == '=')
{
Result[number].typeNumber=26; // '<='
}
else if (inputString[i] == '<')
{
Result[number].typeNumber=27; // '<<'
}
else
{
Result[number].typeNumber=25; // '<'
i--;
}
}
void state15()
{
if (inputString[i] == '=')
{
Result[number].typeNumber=28; // '!='
}
else
{
error();
i--;
}
}
void state16()
{ // 相当于树状结构
while(inputString[i] >= '0' && inputString[i] <= '9')
{ // 当前输入字符为若干个数字时
Result[number].code[k] = inputString[i]; // 把当前输入字符加到内码值中
i++;
k++;
}
if (inputString[i] == '.')
{ // 当前输入字符若为'.'时,则转到状态17;若为'E|e'时,转到状态19;若为其他字符时,到达终态,识别出常数,并且标记种别为110
Result[number].code[k] = inputString[i];
i++;
k++;
state17();
}
else if (inputString[i] == 'E' || inputString[i] == 'e')
{
Result[number].code[k] = inputString[i];
i++;
k++;
state19();
}
else
{
end();
}
}
void state17()
{
if (inputString[i] >= '0' && inputString[i] <= '9')
{
Result[number].code[k] = inputString[i];
i++;
k++;
// 双方同步后移
state18();
}
else
{
error(); // '.'后无内容
}
}
void state18()
{
while(inputString[i] >= '0' && inputString[i] <= '9')
{ // 当前输入字符为若干个数字时
Result[number].code[k] = inputString[i]; // 把当前输入字符加到内码值中
i++;
k++;
}
if (inputString[i] == 'E' || inputString[i] == 'e')
{
Result[number].code[k] = inputString[i];
i++;
k++;
state19();
}
else
{
end();
}
}
void state19()
{
if (inputString[i] == '-' || inputString[i] == '+')
{ // 指数携带了正负号
Result[number].code[k] = inputString[i];
i++;
k++;
state20();
}
else if (inputString[i] >= '0' && inputString[i] <= '9')
{
Result[number].code[k] = inputString[i];
i++;
k++;
state21();
}
else
{
error(); // 'E|e'后无内容
}
}
void state20()
{
if (inputString[i] >= '0' && inputString[i] <= '9')
{
Result[number].code[k] = inputString[i];
i++;
k++;
state21();
}
else
{
error(); // '+|-'后无内容
}
}
void state21()
{
while(inputString[i] >= '0' && inputString[i] <= '9')
{ // 当前输入字符为若干个数字时
Result[number].code[k] = inputString[i]; // 把当前输入字符加到内码值中
i++;
k++;
}
end();
}
void output()
{ // (4)测试
cout << endl << "词法分析结果(种别编码,内码值):" << endl << "output: ";
for (int i=0; i <= number; i++)
{
cout << "(" << Result[i].typeNumber << ", " << Result[i].code << ")";
if (i != number)
{
cout << ',';
}
else
{
// cout << endl;
;
}
}
// cout << "number: " << number << "\t typeNumber: " << Result[number].typeNumber << "\t Result[number].code: " << Result[number].code << endl;
}
void error()
{ // 错误态
Result[number].typeNumber = 0; // 上面的情况都不符合,则表示输入的字符非法,置种别为0,内码值为"Error"
strcpy(Result[number].code, "Input Error!");
}
void end()
{ // 终态
Result[number].typeNumber=110; // 常数种类编号为110
Result[number].code[k]='\0'; // 内码值末端加上结束符
i--;
}
int main()
{
// string strings;
// char strings[10];
// gets(strings);
// cin >> strings;
words(); // 词法分析
// keyWord(); // 判断识别出的标识符是否为保留字
// keyWord_test(strings);
output();
return 0;
}
// ---------------------------------------------------------------------- testing -------------------------------------------------------------------------------
/*
int main() {
// (2)构造状态转换图(自动机)
// char InputString[100]; // 字符数组存放输入串
string inputString;
cin >> inputString;
// while(inputString[i] == ' ') i++; // 剔除空格
// test
cout << "inputString: " << inputString;
cout << "KW: " << KW[2];
// 整体模块设计
words(); // 词法分析
keyWord(); // 判断识别出的标识符是否为保留字
// 为每个非终态编写函数,其中staten()表示状态n的函数。
return 0;
}
void keyWord_test(char *strings)
{
int i;
cout << "function: keyWord(): " << endl;
for (i=0; i < 6; i++)
{ // 目前共有6个保留字
if (strcmp(strings, KW[i]) == 0)
{ // 将标识符与保留字进行比较
// Result[number].typeNumber = i+1; // 种别编码刚好是保留字下标+1
// strcpy(Result[number].code, "-1");
cout << "这是保留字!";
break;
}
// cout << i << endl;
if (i == 5)
{ // 不属于前6个保留字
cout << "这不是一个保留字!";
}
}
}
*/
Note:简单起见,除标识符、常数外,其余单词均为一个单词一类(如一个保留字一类,一个运算符一类),则标识符、常数的内码值为自身的值,其余单词的种别编码代表了它自身的值,故内码值用 -1表示。