編制一個讀單詞過程,源程序為一個文件,讀取該文件,識別出各個具有獨立意義的單詞,即基本保留字、標識符、常數、運算符、界符五大類。並依次輸出各個單詞的內部編碼及單詞符號自身值。
單詞的內部編碼如下:
1、保留字:if、int、for、while、do、return、break、continue;單詞種別碼為1;
2、標識符:除保留字外的以字母開頭,后跟字母、數字的字符序列;單詞種別碼為2;
3、常數為無符號整形數;單詞種別碼為3;
4、運算符包括:+、-、*、/、=;單詞種別碼為4;
5、分隔符包括:,、;、{、}、(、); 單詞種別碼為5。
1、詞法分析器的功能和輸出格式
詞法分析器的功能是輸入源程序,輸出單詞符號。詞法分析器的單詞符號常常表示成以下的二元式(單詞種別碼,單詞符號的屬性值)。本實驗中,采用的是一類符號一種種別碼的方式。
2、各類單詞的文法
<標識符>→<字母><字母數字串>
<字母數字串>→<字母><字母數字串>|<數字><字母數字串>|ε
<無符號整數>→<數字>|<數字><無符號整數>
<運算符>→ + | - | * | / | =
<界符>→ , | ; | ( | ) | { | }
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
/* 各種變量的定義 */
string keywords[36] = { "char", "short", "int", "unsigned", "long", "float", "double",
"struct", "union", "void", "enum", "const", "typedef", "auto",
"static", "break", "case", "continue", "default", "do", "else",
"for", "if", "return", "switch", "while", "sizeof", "printf",
"FILE", "fopen", "NULL", "fclose", "exit", "read", "close",
"fprintf" };
char delimiters[] = { '[', ']', '(', ')', '{', '}', '\'', '\"', ',', ';', ':' };
char operators[5] = { '+', '-', '*', '/', '=' };
ifstream infile; /* 輸入文件 */
ofstream outfile; /* 輸出文件 */
char buffer1[64]; /* 緩沖數組 1*/
char buffer2[64]; /* 緩沖數組 2*/
char *pointer; /* 掃描指針 */
/* 各種函數的聲明 */
bool isChar(char c);/* 是否是字母 */
bool isDigit(char c);/* 是否是 0-9*/
bool isUnderline(char c);/* 是否是下划線 */
bool isEnter(char c);/* 是否是換行 */
bool isDelimiter(char c);/* 是否是界符 */
bool isOperator(char c);/* 是否是運算符 */
int getLength(char *s);/* 求一個字符串的長度 */
bool isIdentifier(char *s);/* 是否是標識符 */
bool isNumber(char *s);/* 是否為數字 */
bool isKeyword(string s);/* 是否是關鍵字 */
char getChar();/* 實現雙緩沖掃描文件 */
void write(string str1, string str2);/* 寫入文件,並且在屏幕上打印 */
/* 程序入口: main 函數 */
int main()
{
char cc = '\0';
string str = "";
pointer = buffer1;
buffer1[63] = buffer2[63] = -1; // 數組尾數值為 -1
infile.open("in.txt", ios::binary);// 二進制文件 outfile.open ("out.txt",ios::trunc);// 再次寫入覆蓋文件已有內容
for (int i = 0; i <= 62; i++)
buffer1[i] = infile.get();// 將文件中字符放入第一緩沖區
for (;;)
{
str = "";
cc = getChar();
str += cc;
AAA: if (isDelimiter(cc))/* 是否是界符 */
{
write(" 分隔符 ", str);
}
else if (isOperator(cc))/* 是否是操作符 */
{
write(" 運算符 ", str);
}
else if (isEnter(cc))/* 是否是換行符 */
{
write(" 換行 ", "\\n");
}
else if (isUnderline(cc) || isChar(cc))/* 是否是標識符 */
{
for (;;)
{
cc = getChar();
if (!(isChar(cc) || isDigit(cc) || isUnderline(cc)))
{
if (isKeyword(str))
{
write(" 保留字 ", str);
}
else{
write(" 標識符 ", str);
}
str = cc;
goto AAA;
}
str += cc;
}
}
else if (isDigit(cc))/* 是否是數字 */
{
for (;;)
{
cc = getChar();
if (!(isDigit(cc)) && cc != '.')
{
write(" 常數 ", str);
str = cc;
goto AAA;
}
str += cc;
}
}
}
return 0;
}
/**********************************************************************/
/* 雙緩沖掃描文件 */
char getChar()
{
if (*pointer == -1) /* 當前指針在緩沖區(不知是那個緩沖區)末尾 */
{
if (pointer == buffer1 + 63)/* 在第一 buffer 尾,向第二 buffer 讀入數據 */
{
for (int i = 0; i <= 62; i++)
{
buffer2[i] = infile.get();
}
pointer = buffer2;
return getChar();
}
else if (pointer == buffer2 + 63)/* 在第二 buffer 尾,向第一 buffer 讀入數據 */
{
for (int i = 0; i <= 62; i++)
{
buffer1[i] = infile.get();
}
pointer = buffer1;
return getChar();
}
else/* 在不是 buffer 尾的位置讀到了 EOF, 說明完成了分析 */
{
infile.close();
outfile.close();
ofstream out;
cout << "\n\n\t 詞法分析完畢! " << endl;
system("pause");
exit(-1);
}
}
return *pointer++;
}
/* 是否是字母 */
bool isChar(char c)
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
{
return true;
}
else
{
return false;
}
}
/* 是否是 0-9*/
bool isDigit(char c)
{
if (c >= '0' && c <= '9')
{
return true;
}
else
{
return false;
}
}
/* 是否是下划線 */
bool isUnderline(char c)
{
if (c == '_')
{
return true;
}
else
{
return false;
}
}
/* 是否是換行 */
bool isEnter(char c)
{
if (c == '\n')
{
return true;
}
else
{
return false;
}
}
/* 是否是界符 */
bool isDelimiter(char c)
{
for (int i = 0; i<10; i++)
{
if (c == delimiters[i])
{
return true;
}
}
return false;
}
/* 是否是運算符 */
bool isOperator(char c)
{
for (int i = 0; i<5; i++)
{
if (c == operators[i])
{
return true;
}
}
return false;
}
/* 求一個字符串的長度 */
int getLength(char *s)
{
int len = 0;
for (int i = 0;; i++)
{
if (s[i] != '\0')
{
len++;
}
else
{
return len;
}
}
}
/* 是否是標識符 */
bool isIdentifier(char *s)
{
int len = getLength(s);
if (isChar(s[0]) || isUnderline(s[0]))
{
for (int i = 1; i<len; i++)
{
if (!(isDigit(s[i]) || isDigit(s[i]) || isUnderline(s[i])))
{
return false;
}
}
return true;
}
else
{
return false;
}
}
/* 是否為數字 */
bool isNumber(char *s)
{
int len = getLength(s);
if (s[0] >= 1 && s[0] <= 9)
{
for (int i = 0; i<len; i++)
{
if (!isDigit(s[i]) && s[i] != '.')
{
return false;
}
}
return true;
}
else
{
return false;
}
}
/* 是否是關鍵字 */
bool isKeyword(string s)
{
for (int i = 0; i<keywords->length(); i++)
{
if (s == keywords[i])
{
return true;
}
}
return false;
}
/* 寫入文件,並且在屏幕上打印 */
void write(string str1, string str2)
{
cout << str1 << " :" << str2 << endl;
outfile << "[ <" << str1 << "> : \"" << str2 << "\" ]" << endl;
}
- 實驗結果


-
個人體會
這個實驗讓我認識到了詞法掃描器的構建過程,以及如何用C++實現。
