“semantic”是語義分析器。語義分析器的輸入流是語法樹,根據對語法樹的語義分析,在輸出中用指定的顏色標記出指定的點。當無數個指定的點被依次標記出時,人眼認為“畫”出了一條線。
要在VS上實現畫出一條線有 2種方法:VC和BC。
“VC”是用Windows自帶圖形庫實現的詞法分析器,程序結果輸出函數繪圖語言解釋器編譯后的圖形,通過改變main.cpp中的WinMain()Window程序主函數中,strcpy(SrcFilePath,"test1.txt");第二個參數來改變要讀取的文件。“BC”是用EGE圖形庫實現的詞法分析器,程序結果輸出函數繪圖語言解釋器編譯后的圖形,通過改變main.cpp中的Parser()函數參數來改變要讀取的文件。
step1
semantic.h
//#ifdef #endif 是預編譯處理的宏語句 #ifdef _VC_COMPILER #include<windows.h> #include<wingdi.h> extern HDC hDC; #endif // _VC_COMPILER //“VC_Compiler”是用Windows自帶圖形庫實現的詞法分析器,程序結果輸出函數繪圖語言解釋器編譯后的圖形 #ifdef _BC_COMPILER #include<graphics.h> #include<conio.h> #endif // _BC_COMPILER #include"parser.h" //“BC_Compiler”是用EGE圖形庫實現的詞法分析器,程序結果輸出函數繪圖語言解釋器編譯后的圖形 #ifdef _VC_COMPILER #define red RGB(255,0,0) //紅色 #define black RGB(0,0,0) //黑色 #endif // _VC_COMPILER #ifdef _BC_COMPILER #define white 255 //白色 #endif // _BC_COMPILER //----------外部函數聲明 extern void DrawPixel(unsigned long x,unsigned long y);//繪制一個點 extern double GetExprValue(struct ExprNode* root);//獲得表達式的值 extern void DrawLoop(double Start,double End,double Step,struct ExprNode* HorPtr,struct ExprNode* VerPtr);//圖形繪制 extern void DelExprTree(struct ExprNode* root);//刪除一棵樹 #ifdef _BC_COMPILER extern int InGraphMode; extern int InitGraph(void); extern void CloseGraph(void); #endif // _BC_COMPILER
step2
semantic.c
#include"semantic.h" extern double Parameter,//參數T的存儲空間:記錄t每次加一點的變化 在語法分析中聲明的 Origin_x,Origin_y,//橫縱坐標平移距離 Scale_x,Scale_y,//橫縱比例因子 Rot_angle;//旋轉角度 double GetExprValue(struct ExprNode* root);//獲得表達式的值 void DrawPixel(unsigned long x,unsigned long y);//繪制一個點 void DrawLoop(double Start,double End,double Step,struct ExprNode* HorPtr,struct ExprNode* VerPtr);//圖形繪制 void DelExprTree(struct ExprNode* root);//刪除一棵樹 static void Errmsg(char *string);//出錯處理 static void CalcCoord(struct ExprNode *Hor_Exp,struct ExprNode *Ver_Exp,double &Hor_x,double &Ver_y);//計算點的坐標 //----------出錯處理 void Errmsg(char *string) { exit(1); } //----------計算被繪制點的坐標 static void CalcCoord(struct ExprNode *Hor_Exp,//橫坐標表達式語法樹的根節點 struct ExprNode *Ver_Exp,//縱坐標表達式語法樹的根節點 double &Hor_x,//點橫坐標值,起返回值的作用 double &Ver_y)//點縱坐標值,起返回值的作用 { double HorCord,VerCord,Hor_tmp; HorCord=GetExprValue(Hor_Exp); VerCord=GetExprValue(Ver_Exp);//根據表達式的語法樹計算原始坐標 HorCord *=Scale_x; VerCord *=Scale_y;//進行比例變換 Hor_tmp=HorCord*cos(Rot_angle)+VerCord*sin(Rot_angle); VerCord=VerCord*cos(Rot_angle)-HorCord*sin(Rot_angle); HorCord = Hor_tmp; //進行旋轉變換 HorCord+=Origin_x; VerCord += Origin_y; //進行平移變換 Hor_x=HorCord; Ver_y = VerCord; //返回變換后點的坐標 }//沒有返回值 //----------循環繪制點的坐標 void DrawLoop(double Start,//起始 double End,//終止 double Step,//步長 struct ExprNode* HorPtr,//橫坐標表達式語法樹的根節點 struct ExprNode* VerPtr)//縱坐標表達式語法樹的根節點 { extern double Parameter; double x,y; for(Parameter=Start;Parameter<=End;Parameter+=Step)//把t在范圍內的每一個值帶入計算 { CalcCoord(HorPtr,VerPtr,x,y);//計算要繪制店的實際坐標 DrawPixel((unsigned long)x,(unsigned long)y);//繪制這個點 } } //----------計算表達式的值 double GetExprValue(struct ExprNode *root)//參數是表達式的根 {//后續遍歷語法樹 根據不同的節點類型計算當前根節點的值 if(root==NULL) return 0.0; switch(root->OpCode) { //二元運算符 case PLUS : return GetExprValue(root->Content.CaseOperater.Left)+GetExprValue(root->Content.CaseOperater.Right); case MINUS : return GetExprValue(root->Content.CaseOperater.Left)-GetExprValue(root->Content.CaseOperater.Right); case MUL : return GetExprValue(root->Content.CaseOperater.Left)*GetExprValue(root->Content.CaseOperater.Right); case DIV : return GetExprValue(root->Content.CaseOperater.Left)/GetExprValue(root->Content.CaseOperater.Right); case POWER : return pow(GetExprValue(root->Content.CaseOperater.Left),GetExprValue(root->Content.CaseOperater.Right)); // 函數調用 case FUNC : return (*root->Content.CaseFunc.MathFuncPtr)(GetExprValue(root->Content.CaseFunc.Child)); // 常數 case CONST_ID : return root->Content.CaseConst; // 參數 case T : return *(root->Content.CaseParmPtr); default : return 0.0; }//返回值是表達式的值 } //----------刪除一顆語法樹 void DelExprTree(struct ExprNode *root) { if(root==NULL) return; switch(root->OpCode) { case PLUS : //二元::兩個孩子的內部節點 case MINUS : case MUL : case DIV : case POWER : DelExprTree(root->Content.CaseOperater.Left); DelExprTree(root->Content.CaseOperater.Right); break; case FUNC : //一元::一個孩子的內部節點 DelExprTree(root->Content.CaseFunc.Child); break; default : //葉子節點 break; } delete(root); //刪除節點 } #ifdef _BC_COMPILER int INGraphMode = 0; int InitGraph(void) { int gd=DETECT,gm; if(InGraphMode) return; registerbgidriver(EGAVGA_driver); initgraph(&gd,&gm,""); setcolor(-1); InGraphMode=1; return 1; } void CloseGraph(void) { if(!InGraphMode) return; getch(); closegraph(); InGraphMode=0; } #endif // _BC_COMPILER //----------繪制一個點 void DrawPixel(unsigned long x,unsigned long y) { #ifdef _VC_COMPILER SetPixel(hDC,x,y,black); #endif // _VC_COMPILER #ifdef _BC_COMPILER putpixel(x,y,red); #endif // _BC_COMPILER }
step3
BC方法
#include"semantic.h" int main() { if(!InitGraph()) return -1; Parser("test4.txt"); CloseGraph(); return 0; }
VC方法
#include"semantic.h" #define MAX_CHARS 200 HDC hDC; //窗口句柄,全局變量 char SrcFilePath[MAX_CHARS]; //用於存放源程序文件路徑 static char Name[]="Compiler"; //窗口名 //----------初始化窗口函數聲明 static bool PrepareWindow(HINSTANCE,HINSTANCE,int); //----------檢查源程序文件是否合法函數聲明 static bool CheckSrcFile(LPSTR); //----------窗口消息處理函數聲明 static LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); //----------轉換函數 wchar_t * ChartoWChar(char *CStr) { size_t len = strlen(CStr) + 1; size_t converted = 0; wchar_t *WStr; WStr = (wchar_t*)malloc(len*sizeof(wchar_t)); mbstowcs_s(&converted, WStr, len, CStr, _TRUNCATE); return WStr; } //----------Window程序主函數 int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { //保存原文件路徑 strcpy(SrcFilePath,"test5.txt"); //初始化窗口 if(PrepareWindow(hInstance,hPrevInstance,nCmdShow)!=true) { MessageBox(NULL, ChartoWChar("Window Initialize failed !"), ChartoWChar("ERROR !"),MB_OK); return 1; } //檢查要分析的源程序文件 if(!CheckSrcFile(SrcFilePath)) return 1; //------------------------------------ //調用繪圖語言解釋器 Parser(SrcFilePath); //------------------------------------ //進入window消息循環 MSG Msg; while(GetMessage(&Msg,NULL,0,0)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; } //----------初始化窗口函數實現 bool PrepareWindow(HINSTANCE hInst,HINSTANCE hPrevInstance,int nCmdShow) { HWND hWnd; WNDCLASS W; memset(&W,0,sizeof(WNDCLASS)); W.style=CS_HREDRAW|CS_VREDRAW; W.lpfnWndProc=WndProc; W.hInstance=hInst; W.hCursor=LoadCursor(NULL,IDC_ARROW); W.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); W.lpszClassName= ChartoWChar(Name); RegisterClass(&W); hWnd=CreateWindow(ChartoWChar(Name), ChartoWChar(Name),WS_OVERLAPPEDWINDOW,10,10,740,490,NULL,NULL,hInst,NULL); if(hWnd==NULL) return false; ShowWindow(hWnd,nCmdShow); UpdateWindow(hWnd); SetCursor(LoadCursor(hInst,IDC_ARROW)); hDC=GetDC(hWnd); return true; } //----------檢查源程序文件是否合法函數實現 bool CheckSrcFile(LPSTR lpszCmdParam) { FILE *file=NULL; if(strlen(lpszCmdParam)==0) { MessageBox(NULL, ChartoWChar("Source File Not Specified "), ChartoWChar("ERROR"), MB_OK); return false; } if((file=fopen(lpszCmdParam,"r"))==NULL) { MessageBox(NULL, ChartoWChar("Open Source File Error !"), ChartoWChar("ERROR"),MB_OK); MessageBox(NULL, ChartoWChar(lpszCmdParam), ChartoWChar("Filename"),MB_OK); return false; } else fclose(file); return true; } //----------窗口處理函數實現 LRESULT CALLBACK WndProc(HWND hWnd,UINT Message,WPARAM wParam,LPARAM lParam) { switch(Message) { case WM_DESTROY : ReleaseDC(hWnd,hDC); PostQuitMessage(0); return 0; //break; case WM_PAINT: PAINTSTRUCT pt; BeginPaint(hWnd,&pt); Parser(SrcFilePath); EndPaint(hWnd,&pt); default : return DefWindowProc(hWnd,Message,wParam,lParam); } }