1. 程式人生 > >編譯原理 詞法分析 原始碼

編譯原理 詞法分析 原始碼


#include<iostream>
#include<string>
#include<fstream>

#include<vector>

// C++中的一種資料結構,確切的說是一個類.它相當於一個動態的陣列,當程式設計師無法知道自己需要的陣列的規模多大時,用其來解決問題可以達到最大節約空間的目的.

using namespace std;


vector <string> Char;//存放char型識別符號的容器
vector <string> Double;//存放double型識別符號的容器
vector <string> Float;//存放float型識別符號的容器
vector <string> Int;//存放int型識別符號的容器
vector <string> String;//存放string型識別符號的容器




bool pChar = 0;//判斷一個字串是否為char型識別符號
bool pDouble = 0;//判斷一個字串是否為double型識別符號
bool pFloat = 0;//判斷一個字串是否為float型識別符號
bool pInt = 0;//判斷一個字串是否為int型識別符號
bool pString = 0;//判斷一個字串是否為string型識別符號


void fhb()//符號表的顯示
{
string filename2;
int i;
int add = 0;//地址
/*cout << "請輸入符號表的名稱:";
cin >> filename2;*/
filename2 = "fb.txt";
ofstream f2(filename2, ios::out);
f2 << "型別" << '\t' << "變數" << '\t' << "地址" << endl;


cout << endl;
cout << "型別" << '\t' << "變數" << '\t' << "地址" << endl;
for (i = 0; i<Char.size(); i++)
{
cout << "char" << '\t' << Char[i] << '\t' << add << endl;
f2 << "char" << '\t' << Char[i] << '\t' << add << endl;
add++;
}
for (i = 0; i<Double.size(); i++)
{
cout << "double" << '\t' << Double[i] << '\t' << add << endl;
f2 << "double" << '\t' << Double[i] << '\t' << add << endl;
add++;
}
for (i = 0; i<Float.size(); i++)
{
cout << "float" << '\t' << Float[i] << '\t' << add << endl;
f2 << "float" << '\t' << Float[i] << '\t' << add << endl;
add++;
}
for (i = 0; i<Int.size(); i++)
{
cout << "int" << '\t' << Int[i] << '\t' << add << endl;
f2 << "int" << '\t' << Int[i] << '\t' << add << endl;
add++;
}
for (i = 0; i<String.size(); i++)
{
cout << "string" << '\t' << String[i] << '\t' << add << endl;
f2 << "string" << '\t' << String[i] << '\t' << add << endl;
add++;
}
f2.close();
}
void Show(char buff[])
{//字串顯示函式
int i = 0;
while (buff[i])
{
cout << buff[i];
i++;
}
}


void File(char ch[])
{//對要開啟的檔案的操作
char c;
char filename[20];//要開啟的檔名
int j = 0;
cout << "請輸入文法所在的檔案的名稱:";
cin >> filename;
FILE *cfPtr;
if ((cfPtr = fopen(filename, "r")) == NULL)
cout << "檔案未找到!";
else
{
while (!feof(cfPtr))//feof是C語言標準庫函式,其原型在stdio.h中,其功能是檢測流上的檔案結束符,如果檔案結束,則返回非0值,否則返回0
{
c = fgetc(cfPtr);
ch[j] = c;//從檔案中一一提取字元
j++;
}
}
cout << endl;
cout << "詞法分析結果如下:\n" << endl;
}


bool isLetter(char c)
{//判斷讀入的字元是否為字母
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
{
return true;
}
else
return false;
}


bool isDigit(char c)
{//判斷是否為數字
if (c >= '0'&&c <= '9')
{
return true;
}
else
return false;
}


bool isKey(char *string)
{//判斷是否為保留字
if (!strcmp(string, "void") || !strcmp(string, "if") || !strcmp(string, "for") || !strcmp(string, "while") || !strcmp(string, "do")
|| !strcmp(string, "return") || !strcmp(string, "break") || !strcmp(string, "main") || !strcmp(string, "int")
|| !strcmp(string, "float") || !strcmp(string, "char") || !strcmp(string, "double") || !strcmp(string, "String"))
{
return true;
}
else
return false;
}


bool isTODKey(char *string)
{//判讀是否為資料型別保留字
if (!strcmp(string, "int") || !strcmp(string, "float") || !strcmp(string, "char") || !strcmp(string, "double") || !strcmp(string, "String"))
{
return true;
}
else return false;
}


int judgTODKey(char *string)
{//判斷保留字型別
if (!strcmp(string, "char")) return 1;
if (!strcmp(string, "double")) return 2;
if (!strcmp(string, "float")) return 3;
if (!strcmp(string, "int")) return 4;
if (!strcmp(string, "String")) return 5;
}


bool isOperator(char ch)
{//判斷是否為運算子
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=')
{
return true;
}
else
return false;
}


bool isSeparator(char ch)
{//判斷是否為分隔符
if (ch == ';' || ch == '{' || ch == '}' || ch == '(' || ch == ')' || ch == ',' || ch == '"')
{
return true;
}
else
return false;
}


//讀取檔案中的字串
void outFile(char buff[], string filename1)
{
int i = 0;
ofstream f1(filename1, ios::app);
while (buff[i])
{
f1 << buff[i];
i++;
}
}


//首字元為字母的分析
void Aletter(char buff[], string filename1)
{
ofstream f1(filename1, ios::app);


if (isKey(buff))
{
cout << "(  1 ,";
Show(buff);
cout << "  )";
cout << "  保留字  " << endl;
outFile(buff, filename1);
f1 << '\t';
f1 << "  1  ";
f1 << '\t';
f1 << "  保留字  " << endl;
if (isTODKey(buff))
{//判斷是否為資料型別的保留字
if (judgTODKey(buff) == 1) pChar = 1;//檢測到相應保留字後,開啟開關
if (judgTODKey(buff) == 2) pDouble = 1;
if (judgTODKey(buff) == 3) pFloat = 1;
if (judgTODKey(buff) == 4) pInt = 1;
if (judgTODKey(buff) == 5) pString = 1;
}
}
else
{
cout << "(  2 ,";
Show(buff);
cout << "  )";
cout << "  識別符號  " << endl;
outFile(buff, filename1);
f1 << '\t';
f1 << "  2  ";
f1 << '\t';
f1 << "  識別符號  " << endl;
if (pChar)
{//pChar開啟時,就將這個字串放入pChar中
Char.push_back(buff);
}
if (pDouble)
{//pDouble開啟時,就將這個字串放入pDouble中
Double.push_back(buff);//字串之後插入一個字元
}
if (pFloat)
{//pFloat開啟時,就將這個字串放入pFloat中
Float.push_back(buff);//字串之後插入一個字元
}
if (pInt)
{//pInt開啟時,就將這個字串放入pInt中
Int.push_back(buff);//字串之後插入一個字元
}
if (pString)
{//pString開啟時,就將這個字串放入pString中
String.push_back(buff);//字串之後插入一個字元
}
}
f1.close();
}


//首字元為數字的分析
void Adigit(char buff[], string filename1)
{
ofstream f1(filename1, ios::app);


bool b = 1;
int i = 0;
while (buff[i])
{
if (isLetter(buff[i]))
{
Show(buff);
cout << "為語法錯誤!" << endl;
b = 0;
break;
}
i++;
}
if (b)
{
cout << "(  3 ,";
Show(buff);
cout << "  )";
cout << "  常數  " << endl;
outFile(buff, filename1);
f1 << '\t';
f1 << "  3  ";
f1 << '\t';
f1 << "  常數  " << endl;
}
f1.close();
}


void main()
{
char ch[500] = "";//存取檔案中讀出的字串
File(ch);
char buff[40] = "";//存放需要比對的字串
int j = 0;


string filename1;//進行儲存內容的檔名
/*cout << "請輸入要進行儲存內容的檔名:";
cin >> filename1;*/
filename1 = "RESULT.txt";


ofstream f1(filename1, ios::app);
f1 << "字串" << '\t' << "符號" << '\t' << "型別" << endl;
while (ch[j] >= 0)
{//對整個字串進行分析直到0
memset(buff, 0, sizeof(buff));//清空buff
int i = 0;
while (!isspace(ch[j]) && !isOperator(ch[j]) && !isSeparator(ch[j]))
{
buff[i] = ch[j];
j++;
i++;
}
//分析buff[]陣列
if (isLetter(buff[0]))
{
Aletter(buff, filename1);
}
if (isDigit(buff[0]))
{
Adigit(buff, filename1);
}
if (isOperator(ch[j]))
{
cout << "(  4 ," << ch[j] << "  )" << "  運算子  " << endl;
ofstream f1(filename1, ios::app);
f1 << ch[j] << '\t' << "  4  " << '\t' << "  運算子  " << endl;
f1.close();
}
if (isSeparator(ch[j]))
{
if (ch[j] == ';'&&pChar == 1)
pChar = 0;//遇到分號時,就關閉開關,結束識別符號的接收
if (ch[j] == ';'&&pDouble == 1)
pDouble = 0;//遇到分號時,就關閉開關,結束識別符號的 接收
if (ch[j] == ';'&&pFloat == 1)
pFloat = 0;//遇到分號時,就關閉開關,結束識別符號的接收
if (ch[j] == ';'&&pInt == 1)
pInt = 0;//遇到分號時,就關閉開關,結束識別符號的接收
if (ch[j] == ';'&&pString == 1)
pString = 0;//遇到分號時,就關閉開關,結束識別符號的接收
cout << "(  5 ," << ch[j] << "  )" << "  分隔符  " << endl;
ofstream f1(filename1, ios::app);
f1 << ch[j] << '\t' << "  5  " << '\t' << "  分隔符  " << endl;
f1.close(); 
}
j++;
}
fhb();
}