編譯原理解釋器(三)C語言語義分析器的實現


“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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM