?? 3.cpp
字號(hào):
/*
* 程序名稱:編譯原理之詞法分析器
* 輸 入:Test.c C語(yǔ)言源程序文件
* 輸 出:Const.txt 常量表 Sign.txt 標(biāo)識(shí)符表 Result.txt 二元式結(jié)果
* 編寫時(shí)間:2007-4-16
* 作 者:1234
* 編譯環(huán)境:VC6.0_CN
* 操作系統(tǒng):WinXP_SP2
* 程序版本:V1.0
* 備 注:此程序采用一緩沖方式讀入程序源碼,首先進(jìn)行預(yù)處理去掉注釋和無(wú)效空格
* 然后再進(jìn)行詳細(xì)的詞法分析,為了便于后續(xù)處理,程序設(shè)置了幾個(gè)表:符號(hào)
* 表和常數(shù)表。
* 注 意:此分析器只對(duì)C語(yǔ)言子集進(jìn)行處理
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>
#include <iostream.h>
#define KEYWORD_LEN 32 //保留字個(gè)數(shù)
#define STR_MAX_LEN 300 //標(biāo)識(shí)符最大長(zhǎng)度
#define PRO_MAX_LEN 20480 //源程序最大長(zhǎng)度
#define STB_MAX_LEN 1000 //符號(hào)表最大容量
#define CTB_MAX_LEN 1000 //常數(shù)表最大容量
#define ERROR 0 //錯(cuò)誤
#define ID (1) //標(biāo)識(shí)符
#define CONST (3) //常量
#define OPERAT (4) //運(yùn)算符
#define DIVIDE (2) //界符
int errorLine=0;
char proBuffer[PRO_MAX_LEN] = ""; //存儲(chǔ)程序代碼的全局緩沖區(qū)
char ch; //讀出來(lái)的當(dāng)前字符
char wordget[STR_MAX_LEN]; //標(biāo)識(shí)符 或 常量
int point = 0; //源程序當(dāng)前位置指針
char signTab[STB_MAX_LEN][STR_MAX_LEN]; //符號(hào)表
int pointSTB = 0; //符號(hào)表指針
char constTab[CTB_MAX_LEN][STR_MAX_LEN]; //常量表
int pointCTB = 0; //常數(shù)表指針
char kwTab[KEYWORD_LEN][60]= //保留字表 ??字符指針數(shù)組??
{"PROGRAM","VAR","BEGIN","DIV","END","INTEGER",
"AND","ARRAY","CASE","CONST","DO","DOWNTO","ELSE",
"FILE","FOR","FUNTION","GOTO","IF","IN","LABEL",
"MOD","NIL","NOT","OF","OR","PACKED","PROCEDURE"};
char errorTab[][50]={ //錯(cuò)誤代碼表
/*0*/"未知錯(cuò)誤", /*1*/"非法的字符", /*2*/"不正確的字符常量表達(dá)",
/*3*/"不正確的字符串表達(dá)", /*4*/"不正確的數(shù)字表達(dá)", /*5*/"注釋丟失'*/'"};
typedef struct signDuality //二元表的定義
{
int kind;
int value;
}*pDualistic, Dualistic;
//函數(shù)聲明
void pretreatment(); //預(yù)處理
void ProcError(int id); //錯(cuò)誤
bool GetChar(); //獲得一個(gè)字符不包括結(jié)束標(biāo)記
bool GetBC(); //獲得一個(gè)非空白字符
void Concat(char *str); //將ch連接到str后
int Reserve(char *str); //對(duì)str字符串查找保留字表 若是一個(gè)保留字-返回其編碼 否則返回0
void Retract(); //將搜索指示器回調(diào)一個(gè)字符位置
int InsertId(char *str);//將str串以標(biāo)識(shí)符插入符號(hào)表,并返回符號(hào)表指針
int InsertConst(char *str); //將str串以常數(shù)插入符號(hào)表,并返回常數(shù)表指針
bool wordAnalyse(pDualistic pDu); //詞法分析 true正常
//end
//預(yù)處理 將緩沖區(qū)內(nèi)的源代碼去掉注釋和無(wú)效空格【所謂的無(wú)效空格是指出現(xiàn)在非字符串
// 常量中的空格】
void pretreatment() //預(yù)處理
{int lines=0;
char tmp[PRO_MAX_LEN]; //先將處理結(jié)果保存到臨時(shí)空間,這樣雖然浪費(fèi)空間但是節(jié)約
//時(shí)間
int tmpp = 0; //這個(gè)臨時(shí)空間的末尾指針
bool flg;
char tmpc;
//去掉注釋先
//注釋有兩種 一種是C++風(fēng)格的// 另一種是C風(fēng)格的/**/
point = 0;
do
{
flg = GetChar();
if(ch == '/')
{
flg = GetChar();
switch(ch) // case "/"and "*"
{
case '/':
do
{
flg = GetChar();
}while(!(ch == '\n' || flg == false));// || ch == '\0'));//注釋一直到行尾或文件結(jié)束
if(ch == '\n')
Retract(); //歸還換行函數(shù)
break;
case '*':
do
{
flg = GetChar();
tmpc = ch;
//為了保證出錯(cuò)處理程序能正確定位出錯(cuò)位置 保留注釋中的換行
if(tmpc == '\n')
tmp[tmpp++] = tmpc;
flg = GetChar();
Retract(); //歸還一個(gè)字符函數(shù)
}while(flg && !(flg && tmpc == '*' && ch == '/')); //不以*/
flg = GetChar();
if (!flg)
{
ProcError(5); //錯(cuò)誤調(diào)用函數(shù) 5"注釋丟失'
}
break;
default:
//不是任何一種注釋
Retract(); //將搜索指示器回調(diào)一個(gè)字符位置
Retract(); //將搜索指示器回調(diào)一個(gè)字符位置 “//”或“*/”
GetChar(); //獲得一個(gè)字符不包括結(jié)束標(biāo)記
tmp[tmpp++] = ch;
flg = GetChar();
tmp[tmpp++] = ch; //tmpp臨時(shí)空間的末尾指針
}
}
else
{
tmp[tmpp++] = ch;
}
}while(flg); //flg布爾變量,判斷是否取得字符
tmp[tmpp] = '\0';
strcpy(proBuffer,tmp); // 新取得的字符送入緩沖區(qū)
}
void ProcError(int id) //錯(cuò)誤
{
printf("\nError:第%d行,%s\n",errorLine, errorTab[id]);//errorTab[id]錯(cuò)誤列表
}
bool GetChar()//獲得一個(gè)字符不包括結(jié)束標(biāo)記
{
if(point < PRO_MAX_LEN && proBuffer[point] != '\0')
{//如果當(dāng)前下標(biāo)合法且當(dāng)前字符為結(jié)束標(biāo)記則取字符增游標(biāo)
ch = proBuffer[point++];
if (ch == '\n')
errorLine ++;
return true;
}
ch = '\0';
return false;
}
bool GetBC()//獲得一個(gè)非空白字符
{
do
{
if(!GetChar()) //獲取字符失敗
{
ch = '\0';
return false;
}
}while(isspace(ch)); //直到獲得一個(gè)非空白字符 //isspace(ch)判斷字符ch是否為空白符
return true;
}
void Concat(char *str) //將ch連接到str后
{
int i;
for(i=0; str[i]; ++i);
str[i] = ch;
str[i+1] = '\0';
}
int Reserve(char *str)//對(duì)str字符串查找保留字表 若是一個(gè)保留字-返回其編碼 否則返回0
{
int i;
for(i=0; i<KEYWORD_LEN; ++i) //從保留字表中查找str串
{
if(0 == strcmp(kwTab[i], str))
return i+5; //注意,這里加一原因是0值被錯(cuò)誤標(biāo)記占用
}
return 0;
}
void Retract()///char *ch//將搜索指示器回調(diào)一個(gè)字符位置
{
if(proBuffer[point] == '\n' && errorLine > 0)
errorLine --;
point --;
}
int InsertId(char *str)//將str串以標(biāo)識(shí)符插入符號(hào)表,并返回符號(hào)表指針
{
int i;
for(i=0; i < pointSTB; ++i) // pointSTB符號(hào)表指針
if(0 == strcmp(signTab[i], str))
return i;
strcpy(signTab[pointSTB++], str);
return (pointSTB-1);
}
int InsertConst(char *str)//將str串以常數(shù)插入常量表,并返回常數(shù)表指針
{
int i;
for(i=0; i < pointCTB; ++i) //pointCTB常數(shù)表指針
if(0 == strcmp(constTab[i], str))
return i;
strcpy(constTab[pointCTB++], str);
return (pointCTB-1);
}
//詞法分析 false--分析結(jié)束
bool wordAnalyse(pDualistic pDu) //詞法分析 true正常
{
int code, value;
char judge; //這里有個(gè)技巧 借用此變量巧妙的運(yùn)用SWITCH結(jié)構(gòu)
int i = 0; //輔助
GetBC(); //獲得一個(gè)非空白字符
judge = ch;
if (isalpha(ch) || ch == '_') judge='L';
//isalpha(ch)如果ch的內(nèi)容為字母表中的字母,本函數(shù)返回非零值,否則返回零值。
if (isdigit(ch)) judge='D';
//(isdigit(ch)判斷一個(gè)字符是否為數(shù)字(0-9),是數(shù)字返回1,不是返回0
switch(judge)
{
case 'L':
while(isalnum(ch) || ch == '_')
//isalnum(ch)如果本函數(shù)的變?cè)獮樽帜富驍?shù)字,它將返回非零值,否則返回零值。
{ //標(biāo)識(shí)符
wordget[i++] = ch;
GetChar(); //獲得一個(gè)字符不包括結(jié)束標(biāo)記
}
wordget[i] = '\0';
Retract(); //回退一個(gè)字符
code = Reserve(wordget); //對(duì)str字符串查找保留字表 若是一個(gè)保留字-返回其編碼 否則返回0
if(code == 0)
{
value = InsertId(wordget);//將str串以標(biāo)識(shí)符插入符號(hào)表,并返回符號(hào)表指針
pDu->kind = ID;
pDu->value = value;
}
else
{
pDu->kind = code;
pDu->value = -1;
}
return true;
case 'D':
while(isdigit(ch)) //isdigit(ch)判斷字符ch是否為數(shù)字(0-9),是數(shù)字返回1,不是返回0;
{
wordget[i++] = ch;
GetChar(); //獲得一個(gè)字符不包括結(jié)束標(biāo)記
}
wordget[i] = '\0';
Retract(); //回退一個(gè)字符
value = InsertConst(wordget);//將str串以常數(shù)插入符號(hào)表,并返回常數(shù)表指針
pDu->kind = CONST;
pDu->value= value;
return true;
//( ) [ ] . , ! != ~ sizeof < << <= > >> >= = == & && &= | || |= ?: + ++ +=
// - -> -- -= * *= / /= % %= >>= <<= ^ ^=
case '"':
//字符串常量
do
{
wordget[i++] = ch;
GetChar();
}while(ch != '"' && ch != '\0');
wordget[i++] = ch; wordget[i] = '\0';
if(ch == '\0')
{
printf("%s",wordget);
ProcError(3);
pDu->kind = ERROR;
pDu->value = 0;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -