編譯原理----詞法分析

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要完成的任務:

  1. 濾掉單詞間的空格。
  2. 識別關鍵字,用查關鍵字表的方法識別。當單詞是關鍵字時,將對應的類別放在SYM中。如IF的類別爲IFSYM,THEN的類別爲THENSYM。
  3. 識別標識符,標識符的類別爲IDENT,IDENT放在SYM中,標識符本身的值放在ID中。關鍵字或標識符的最大長度是10。
  4. 拼數,將數的類別NUMBER放在SYM中,數本身的值放在NUM中。
  5. 拼由兩個字符組成的運算符,如:>=、<=等等,識別後將類別存放在SYM中。
  6. 打印源程序,邊讀入字符邊打印。

由於一個單詞是由一個或多個字符組成的,所以在詞法分析程序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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章