zoukankan      html  css  js  c++  java
  • 编译原理解释器(三)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);
        }
    }
  • 相关阅读:
    没有插件的sublime编辑器是没有灵魂的
    原生JS简单的无缝自动轮播
    自学前端的日子,记录我的秃头之旅
    简洁快速的数组去重
    最困难的是带着自己的选择生活下去
    css画图那些事
    css3画图那些事(三角形、圆形、梯形等)
    SVN那些事
    关于使用JQ scrollTop方法进行滚动定位
    linux下mysql出现Access denied for user 'root'@'localhost' (using password: YES)解决方法
  • 原文地址:https://www.cnblogs.com/olivegyr/p/6292606.html
Copyright © 2011-2022 走看看