Description
小C语言文法
-
<程序>→<main关键字>(){<声明序列><语句序列>}
-
<声明序列>→<声明序列><声明语句>|<声明语句>|<空>
-
<声明语句>→<标识符表>;
-
<标识符表>→<标识符>,<标识符表>|<标识符>
-
<语句序列>→<语句序列><语句>|<语句>
-
<语句>→< if语句>|< while语句>|< for语句>|<复合语句>|<赋值语句>
-
< if语句>→< if关键字>(<表达式>)<复合语句>|(<表达式>)<复合语句>< else关键字><复合语句>
-
< while语句>→< while关键字>(<表达式>)<复合语句>
-
< for语句>→< for关键字>(<表达式>;<表达式>;<表达式>)<复合语句>
-
<复合语句>→{<语句序列>}
-
<赋值语句>→<表达式>;
-
<表达式>→<标识符>=<算数表达式>|<布尔表达式>
-
<布尔表达式>→<算数表达式> |<算数表达式><关系运算符><算数表达式>
-
<关系运算符>→>|<|>=|<=|==|!=
-
<算数表达式>→<算数表达式>+<项>|<算数表达式>-<项>|<项>
-
<项>→<项>*<因子>|<项>/<因子>|<因子>
-
<因子>→<标识符>|<无符号整数>|(<算数表达式>)
-
<标识符>→<字母>|<标识符><字母>|<标识符><数字>
-
<无符号整数>→<数字>|<无符号整数><数字>
-
<字母>→a|b|…|z|A|B|…|Z
-
<数字>→0|1|2|3|4|5|6|7|8|9
-
< main关键字>→main
-
< if关键字>→if
-
< else关键字>→else
-
< for关键字>→for
-
< while关键字>→while
-
< int关键字>→int
每行单词数不超过10个
小C语言文法如上,现在我们对小C语言写的一个源程序进行词法分析,分析出关键字、自定义标识符、整数、界符
和运算符。
关键字:main if else for while int
自定义标识符:除关键字外的标识符
整数:无符号整数
界符:{ } ( ) , ;
运算符:= + - * / < <= > >= == !=
#include <iostream>
#include <string>
using namespace std;
string keyword[6] = {"main", "if", "else", "for", "while", "int"};
string boun[6] = {"{", "}", "(", ")", ";", ","};
string oper[8] = {"=", "+", "-", "*", "/", "<", ">", "!"};
// , "<=", ">=", "==", "!=",
//这里只是存储单字符的运算符,这样可以方便下面进行判断,
//由于双字符的运算发第二个都是“=”,所以在判断结束后,需要再判断其下一个字符是否是“=”
//【注意】:不要遗漏“!”
string temp = "";
//★★★这个非常重要,由于关键字、自定义标识符、数字,这三项的长度是不一定的,
//所以如果一个字符既不是界符,也不是运算符,则该字符是上述单词中的一个字符,
//需要存储起来,这里的temp就是存储多字节单词的
void check()//检查存储的单词,是关键字、自定义标识符、数字中的哪一种
{
if (temp == "")//如果没有存储任何单词,直接返回
return;
if (temp[0] >= '0' && temp[0] <= '9')//由于程序一定是合法的,所以只要第一个字符是数字,整个单词就是数字
{
cout << "(integer," << temp << ")" << endl;
temp = "";//该函数中,对单词判断结束后需要将单词置零
return;
}
for (int i = 0; i < 6; i++)
{
if (temp == keyword[i])
{
cout << "(keyword," << temp << ")" << endl;
temp = "";
return;
}
}
cout << "(identifier," << temp << ")" << endl;
temp = "";
return;
}
int main()
{
string str; //定义一个字符串,存放输入的程序字符串
while (cin >> str)//循环输入,直至输入结束
{
int len = str.length(); //计算输入的字符串的长度
for (int i = 0; i < len; i++)//读取每一个字符
{
bool flag = true;//设置一个表示位,用来表示是否已经判断出该字符的词性
// ☆判断是否是界符,这一部分是最简单的,可以优先考虑
for (int j = 0; j < 6; j++)
{
if (str[i] == boun[j][0])
{
//如果遇见界符、运算符或者一行的结束,则标志这单词的结束
check();//判断存储的单词
cout << "(boundary," << str[i] << ")" << endl;//输出界符
flag = false;//置标记位为假
break;
}
}
//如果标记位为假,说明已经判断结束
if (!flag)
continue;
// ☆判断是否是运算符
for (int j = 0; j < 8; j++)
{
if (str[i] == oper[j][0])
{
//如果遇见界符、运算符或者一行的结束,则标志这单词的结束
check();//判断存储的单词
//由于运算符,有单字节和双字节,所以要单独判断其下一个字符
if (i + 1 < len && str[i + 1] == '=')//先判断是否有下一个字符,然后判断是否为“=”
{
cout << "(operator," << str[i] << "=)" << endl;
i++;//★★★一定不要遗漏
}
else
{
cout << "(operator," << str[i] << ")" << endl;
}
flag = false;
break;
}
}
if (!flag)
continue;
//如果程序可以执行到这里,说明上面的两个continue语句都没有执行,说明该字符是多字节单词的一个字节
temp += str[i];
}
//如果遇见界符、运算符或者一行的结束,则标志这单词的结束,当上面的for循环结束,说明一行的结束,也是单词结束的标志
check();
}
}
/*
循环读入程序,读入时将空白字符已经过滤,即读入后不会再有空白字符。
这里可以先将程序分成两部分,第一部分为对界符和运算符的判断,第二部分是对关键字、自定义标识符、整数的判断。
第一部分:
界符的判断只需要按照boun数组进行对比即可,运算符先进行单运算符的对比,然后还要特殊判断两个字符的运算符
第二部分:
这些大部分不是单个字符,所以如何判断一个单词的结束非常重要。
因为读入的字符串没有空格等空白字符,所以判断这一类单词的结束有以下几种情况:
1.读入的这一行字符串已经读取结束。
2.有第一部分的字符读入。
*/