編譯原理----詞法分析
0.PL/0文法
〈程式〉→〈分程式〉.
〈分程式〉→ [<常量說明部分>][<變數說明部分>][<過程說明部分>]〈語句〉
<常量說明部分> → CONST<常量定義>{ ,<常量定義>};
<常量定義> → <識別符號>=<無符號整數>
<無符號整數> → <數字>{<數字>}
<變數說明部分> → VAR<識別符號>{ ,<識別符號>};
<識別符號> → <字母>{<字母>|<數字>}
<過程說明部分> → <過程首部><分程式>;{<過程說明部分>}
<過程首部> → procedure<識別符號>;
<語句> → <賦值語句>|<條件語句>|<當型迴圈語句>|<過程呼叫語句>|<讀語句>|<寫語句>|<複合語句>|<空>
<賦值語句> → <識別符號>:=<表示式>
<複合語句> → begin<語句>{ ;<語句>}<end>
<條件> → <表示式><關係運算符><表示式>|odd<表示式>
<表示式> → [+|-]<項>{<加減運算子><項>}
<項> → <因子>{<乘除運算子><因子>}
<因子> → <識別符號>|<無符號整數>|(<表示式>)
<加減運符> → +|-
<乘除運算子> → *|/
<關係運算符> → =|#|<|<=|>|>=
<條件語句> → if<條件>then<語句>
<過程呼叫語句> → call<識別符號>
<當型迴圈語句> → while<條件>do<語句>
<讀語句> → read(<識別符號>{ ,<識別符號>})
<寫語句> → write(<表示式>{,<表示式>})
<字母> → a|b|c…x|y|z
<數字> → 0|1|2…7|8|9
1.PL/0語言建立一個詞法分程式GETSYM(函式)
要求:
把關鍵字、算符、界符稱為語言固有的單詞,識別符號、常量稱為使用者自定義的單詞。為此設定三個全程量:SYM,ID,NUM 。
SYM:存放每個單詞的類別,為內部編碼的表示形式。
ID:存放使用者所定義的識別符號的值,即識別符號字串的機內表示。
NUM:存放使用者定義的數。
GETSYM要完成的任務:
- 濾掉單詞間的空格。
- 識別關鍵字,用查關鍵字表的方法識別。當單詞是關鍵字時,將對應的類別放在SYM中。如IF的類別為IFSYM,THEN的類別為THENSYM。
- 識別識別符號,識別符號的類別為IDENT,IDENT放在SYM中,識別符號本身的值放在ID中。關鍵字或識別符號的最大長度是10。
- 拼數,將數的類別NUMBER放在SYM中,數本身的值放在NUM中。
- 拼由兩個字元組成的運算子,如:>=、<=等等,識別後將類別存放在SYM中。
- 列印源程式,邊讀入字元邊列印。
由於一個單詞是由一個或多個字元組成的,所以在詞法分析程式GETSYM中定義一個讀字元過程GETCH。
2.自己的實現
將原始碼放入檔案“ex1.txt”,大小寫轉換及去掉註釋後的程式碼放入“ex1_1.txt”,分析之後的結果放入“lex.txt”並且在命令列中打印出來。對於關鍵字、算符、界符,放在了一個表中,在表中的位置即為各自的類別。對於識別符號和數字,其類別固定。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//SYM:存放每個單詞的類別,為內部編碼的表示形式。
//ID:存放使用者所定義的識別符號的值,即識別符號字串的機內表示。
//NUM:存放使用者定義的數。
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
#define size 120
char symTB[29][15] = {
"const","var","procedure","begin","end","odd","if","then","call","while","do","read","write",//0-12
";",",",".",":=","(",")","+","-","*","/","=","#""<","<=",">",">="//13-28
};//關鍵字與算符界符表
//數字 識別符號
#define NUMBER 29
#define IDENT 30
char other[] = "--";
int sym = 0;//指向symTB的指標
char idTB[30][10] = { "" };//識別符號表
int id = 0;//識別符號表指標
char numTB[100][10] = { "" };//數字表
int num = 0;//數字表指標
char ch;//當前讀入的字元
char strToken[15] = "";//當前讀入的字串
int p = 0;//當前讀入的字串的指標
int code, value;//返回資訊
char x[15];
//******************************************
//判斷是否為字母
bool IsLetter(char letter)
{
if ((letter>='a'&&letter<='z') || (letter>='A'&&letter<='Z'))
return true;
else
return false;
}
//******************************************
//判斷是否為數字
bool IsDigit(char digit)
{
if (digit>='0'&&digit<='9')
return true;
else
return false;
}
//******************************************
//查詢關鍵字表,找到返回類別(位置+1)
int Retract(char*te)
{
for (int i = 0; i < 13; i++)
{
if (strcmp(te, symTB[i]) == 0)
{
return i+1;
}
}
return -1;
}
//******************************************
//判斷是否為算符或界符,找到返回位置+1,否則返回-1
int IsSoj(char soj)
{
for (int i = 13; i < 29; i++)
{
if (soj == symTB[i][0])
{
return i + 1;
}
}
return -1;
}
//******************************************
//判斷是否為算符或界符,找到返回位置+1,否則返回-1
int IsSoj(char *soj)
{
for (int i = 13; i < 29; i++)
{
if (strcmp(soj,symTB[i])==0)
{
return i + 1;
}
}
return -1;
}
//******************************************
//從識別符號表中查詢識別符號,如果沒有則插入,最後返回指標(位置)
int InsertId(char*te)
{
for (int i = 0; i < id; i++)
{
if (strcmp(te, idTB[i]) == 0)
{
return i;
}
}
strcpy_s(idTB[id++],strlen(te)+1, te);
return id - 1 ;
}
//******************************************
//從數字表表中查詢識別符號,如果沒有則插入,最後返回指標(位置)
int InsertNum(char*te)
{
for (int i = 0; i < id; i++)
{
if (strcmp(te, numTB[i]) == 0)
{
return i;
}
}
strcpy_s(numTB[num++], strlen(te) + 1, te);
return num - 1;
}
char tran(char te)
{
if (te >= 'A'&&te <= 'Z')
{
te = te + 32;
return te;
}
else
return te;
}
//******************************************
//過濾註釋,將大寫轉換為小寫
void deal(ifstream *sourfile, ofstream *destfile)
{
char tempx;
do
{
tempx = sourfile->get();
if (tempx == '/')
{
char tempy = sourfile->get();
if (tempy == '/')
{
while (sourfile->get() != 10);
tempx = sourfile->get();
}
else if (tempy == '*')
{
char tempz1 = sourfile->get();
char tempz2 = sourfile->get();
while (!(tempz1 == '*'&&tempz2 == '/'))
{
tempz1 = tempz2;
tempz2 = sourfile->get();
if (tempz1 == EOF || tempz2 == EOF)
{
tempx = EOF;
break;
}
}
}
else
{
*destfile << tran(tempx) << tran(tempy);
}
}
else
{
//if (tempx != 10 && tempx != 13 && tempx != 9 && tempx != EOF )
if (tempx != EOF)
*destfile << tran(tempx);
}
} while (tempx != EOF);
return;
}
//******************************************
//
int getsym(ifstream *sourfile, ofstream *destfile)
{
ch = ' ';
while (ch != EOF)
{
p = 0;
sourfile->get(ch);
while (ch == ' '||ch == 10)//過濾空格與換行
ch = sourfile->get();
if (ch == EOF)
{
return 1;
}
if (IsLetter(ch))//讀到的是字母,則要麼是關鍵字,要麼是識別符號
{
strToken[p++] = ch;
sourfile->get(ch);
while (IsDigit(ch) || IsLetter(ch))//如果是數字或字母,則繼續讀取
{
strToken[p++] = ch;
sourfile->get(ch);
}
sourfile->seekg(-1, ios::cur);//回退一格
code = Retract(strToken);//查詢關鍵字表
if (code == -1)
{//沒找到,插入識別符號表
value = InsertId(strToken);
sprintf_s(x,100,"%-15s%-15d%-15d\n", idTB[value], IDENT, value);
printf(x);
*destfile << x;
}
else
{
sprintf_s(x,100,"%-15s%-15d%-15s\n", symTB[code - 1], code, other);
printf(x);
*destfile << x;
}
}
else if (IsDigit(ch))
{
strToken[p++] = ch;
sourfile->get(ch);
while (IsDigit(ch))//如果是數字,則繼續讀取
{
strToken[p++] = ch;
sourfile->get(ch);
}
sourfile->seekg(-1, ios::cur);//回退一格
value = InsertNum(strToken);
string temp(strToken);
int num = atoi(temp.c_str());
sprintf_s(x, 100, "%-15s%-15d%-15d\n", numTB[value], NUMBER, value);
printf(x);
*destfile << x;
//cout << number;
}
else if((code=IsSoj(ch))!=-1)
{
strToken[p++] = ch;
if (ch == ':')
{
sourfile->get(ch);
if (ch == '=')
{
strToken[p++] = ch;
sprintf_s(x,100,"%-15s%-15d%-15s\n", strToken, code, other);
printf(x);
*destfile << x;
}
else
{
sourfile->seekg(-1, ios::cur);//回退一格
printf("error\n");
return -1;
}
}
else if (ch == '>' || ch == '<')
{
sourfile->get(ch);
if (ch == '=')
{
strToken[p++] = ch;
code = IsSoj(strToken);
sprintf_s(x,100,"%-15s-15d%-15s\n", strToken, code, other);
printf(x);
*destfile << x;
}
else
{
sourfile->seekg(-1, ios::cur);//回退一格
sprintf_s(x,100,"%-15s%-15d%-15s\n", strToken, code, other);
printf(x);
*destfile << x;
}
}
else
{
sprintf_s(x, 100, "%-15s%-15d%-15s\n", strToken, code, other);
printf(x);
*destfile << x;
}
}
else
{
printf("error\n");
return -1;
}
ch = ' ';
memset(strToken, 0, sizeof(strToken));
memset(x, 0, sizeof(x));
}
return 1;
}
int main()
{
ifstream openfile("../ex1.txt");
ofstream outfile("../ex1_1.txt", ios::out);
if (!openfile.is_open())
{
cout << "未成功開啟檔案" << endl;
}
deal(&openfile, &outfile);//
openfile.close();
outfile.close();
openfile.open("../ex1_1.txt");
outfile.open("../lex.txt", ios::out);
if (!openfile.is_open())
{
cout << "未成功開啟檔案" << endl;
}
getsym(&openfile, &outfile);//
openfile.close();
outfile.close();
printf("\n\n\n\n");
printf("id table\n");
for (int i = 0; i < id; i++)
{
printf("%-15s%-15d\n", idTB[i], i);
}
printf("\n\n\n\n");
printf("num table\n");
for (int i = 0; i < num; i++)
{
printf("%-15s%-15d\n", numTB[i], i);
}
system("pause");
return 0;
}