实验要求
【任务介绍】根据给定源语言的构词规则,从任意字符串中识别出所有的合法标识符。
【输入】字符串。
【输出】单词符号流,一行一个单词。
【题目】设计一个程序,从任意字符串中识别出所有可视为C语言“名字”的子串。注意:
-
构词规则:以字母打头,后跟任意多个字母、数字的单词;长度不超过15;不区分大小写;把下划线视为第27个字母。
-
关键字保留,即:语言定义中保留了某些单词用作关键字,程序员不可以将这些单词用作“名 字“(变量名、常量名、函数名、标号名等等)。
编程环境和语言
编程语言:C++
IDE:vs 2019
实验原理分析
预处理结束后,因为C语言中的关键字、运算符和界符都是有限个,而标识符则是无限个,所以我们只需要判断一个词不是关键字、运算符、界符、字符串,第一个字符不是数字,那么我们就可以断定这个词就是一个标识符。
程序关键部分分析
用来预处理的函数为pre_process(char *buff, int &in_comment)(相对于实验一的预处理有所修改),用来识别标识符的函数为identifyID(ifstream& fin, ofstream& fout)。
定义
首先,我定义了关键字数组、运算符数组和界符数组,用于后面判断一个字符串是否为标识符:
#define MAXN 1024 //缓冲区的最大容量
char keywords[33][20] = { //关键字,包括main在内共有33个
"auto", "short", "int", "long", "float", "double", "char", "struct",
"union", "enum", "typedef", "const", "unsigned", "signed", "extern",
"register", "static", "volatile", "void", "if", "else", "switch",
"case", "for", "do", "while", "goto", "continue", "break", "default",
"sizeof", "return", "main"
};
char operators[38][10] = { //运算符,共38个
"+", "-", "*", "/", "%", "++", "--", "==", "!=", ">", ">=", "<", "<=",
"&&", "||", "!", "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=",
"^=", "|=", "&", "|", "^", "~", "<<", ">>", "?", ":", ",", ".", "->"
};
char delimiters[7] = { '(', ')', '[', ']', '{', '}', ';' }; //分隔符,共7个
然后定义了几个函数:
bool isKey(char* s); //用来判断字符串是否为关键字,是则返回true,否则返回false
bool isOP(char* s); //用来判断字符串是否为运算符,是则返回true,否则返回false
bool isDE(char s); //用来判断字符是否为分隔符,是则返回true,否则返回false
void pre_process(char *buff, int &in_comment); //预处理
void identifyID(ifstream& fin, ofstream& fout); //将标识符找出并输出
关键部分分析
pre_process()预处理中首先去掉注释,这里的操作与我的上一篇《编译原理实验一:预处理》稍稍有些不同,即并没有将所有的空白字符去掉,可以与我的上一篇进行对照。
while (i < strlen(buff)) { //去注释
cur_c = buff[i++]; //首先将获取的字符存入缓存中
switch (in_comment) {
case 0:
if (cur_c == '\"') { //进入双引号中
data[j++] = cur_c;
in_comment = 3;
}
else if (cur_c == '\'') { //进入单引号中
data[j++] = cur_c;
in_comment = 4;
}
else if (old_c == '/' && cur_c == '*') { //进入多行注释中
j--;
in_comment = 1;
}
else if (old_c == '/' && cur_c == '/') { //进入单行注释中
j--;
in_comment = 2;
}
else { //其他情况则直接将数据写入data中
data[j++] = cur_c;
}
break;
case 1:if (old_c == '*' && cur_c == '/') in_comment = 0; //多行注释结束
break;
case 2:if (i == strlen(buff)) in_comment = 0; //单行注释到这行结束时标志位置为0
break;
case 3:
data[j++] = cur_c;
if (cur_c == '\"') in_comment = 0;
break;
case 4:
data[j++] = cur_c;
if (cur_c == '\'') in_comment = 0;
break;
}
old_c = cur_c; //保留上一个字符
}
pre_process()预处理中,去掉注释的数据存放在data数组中,分隔词后的数据存放在