编译原理解释器,三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.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);
    }
}