简单解释器

题目

为函数绘图语言编写一个解释器,解释器接受用绘图语言编写的源程序,经语法和语义分析之后,将源程序所规定的图形显示在显示屏(或窗口)中。

语法和语义

  • 循环绘图(FOR-DRAW)
  • 比例设置(SCALE)
  • 角度旋转(ROT)
  • 坐标平移(ORIGIN)
  • 注释 (-- 或 //)

循环绘图

  • 语法
    FOR T FROM 起点 TO 终点 STEP 步长 DRAW(横坐标, 纵坐标);
  • 语义
    令T从起点终点、每次改变一个步长,绘制出由(横坐标纵坐标)所规定的点的轨迹。
  • 举例
    FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (cos(T), sin(T));
  • 说明
    该语句的作用是令T从0到2*PI、步长 PI/50,绘制出各个点的坐标(cos(T),sin(T)),即一个单位圆。
  • 注意
    由于绘图系统的默认值是
    ORIGIN IS (0,0);
    ROT IS 0;
    SCALE IS (1, 1);
    所以实际绘制出的图形是在屏幕左上角的一个点。

比例设置

  • 语法
    SCALE IS (横坐标比例因子纵坐标比例因子);
  • 语义
    设置横坐标和纵坐标的比例,并分别按照比例因子进行缩放。

角度旋转

  • 语法
    ROT IS 角度
  • 语义
    逆时针旋转角度所规定的弧度值。具体计算公式:
    旋转后X=旋转前XCOS(角度)+旋转前YSIN(角度)
    旋转后Y=旋转前YCOS(角度)-旋转前XSIN(角度)

坐标平移

  • 语法
    ORIGIN IS (横坐标纵坐标);
  • 语义
    将坐标系的原点平移到横坐标纵坐标规定的点处。

注释

  • 语法
    // This is a comment line

    – 此行是注释
  • 语义
    // 或 – 之后,直到行尾,均是注释

代码

C语言

主函数

/****************************************************************************************\ 
 *
 * <1> 各类语句可以按任意次序书写,且语句以分号结尾。源程序中的语句以它们出现的先后顺序处理。 
 * <2> ORIGIN、ROT和SCALE 语句只影响其后的绘图语句,且遵循最后出现的语句有效的原则。
 *         例如,若有下述ROT语句序列: 	ROT IS 0.7 ;ROT IS 1.57 ;
 *     则随后的绘图语句将按1.57而不是0.7弧度旋转。 
 * <3> 无论ORIGIN、ROT和SCALE语句的出现顺序如何,图形的变换顺序总是:比例变换→旋转变换→平移变换 
 * <4> 语言对大小写不敏感,例如for、For、FOR等,均被认为是同一个保留字。 
 * <5> 语句中表达式的值均为双精度类型,旋转角度单位为弧度且为逆时针旋转,平移单位为点。
 * 
 * 
 \****************************************************************************************/
#include "CMPL_H.h"

extern struct Token token;

int main(int argc, char **argv)
{
    InitScanner(argv[1]);

    static TCHAR szClassName[] = TEXT("Drawbmp");
    HINSTANCE hInstance; HWND     hwnd;
    MSG      msg; WNDCLASS wndclass; 

    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc    = WndProc; 
    wndclass.cbClsExtra     = 0; 
    wndclass.cbWndExtra     = 0; 
    wndclass.hInstance      = hInstance;
    wndclass.hIcon          = LoadIcon (NULL, IDI_APPLICATION);
    wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW);
    wndclass.hbrBackground  = (HBRUSH) GetStockObject (WHITE_BRUSH); 
    // wndclass.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);  //
    wndclass.lpszMenuName   = NULL ; 
    wndclass.lpszClassName  = szClassName; 

    RegisterClass(&wndclass);

    hwnd = CreateWindow(
        szClassName, 
        TEXT("Good Job!"), 
        WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        980,  //窗口宽度
        720,  //窗口高度
        NULL,  //父窗口句柄
        NULL,  //窗口菜单句柄
        hInstance,  
        NULL 
    );

    switch (argc) {
        case 1:
            MessageBox(hwnd, TEXT("you need to drag txtfile on this program."),TEXT("Usage"),MB_OK | MB_ICONWARNING);
            return 0;
            // help();
            // break;
        case 2:
            break;
        case 3:
            // InitScanner(argv[1]);
            if (!strcmp(argv[2], "-w")) {
                PrintToken();
            }
            else if (!strcmp(argv[2], "-s")) {
                ExpressionTest();
            }
            else {
                help();
            }
            break;
        default:
            help();
    }
    ShowWindow (hwnd, 1); UpdateWindow (hwnd);
    
    while( GetMessage(&msg, NULL, 0, 0) ){
        TranslateMessage(&msg); 
        DispatchMessage (&msg); 
    }

    CloseScanner();
    return 0;
}


功能函数

#include "CMPL_H.h"

struct Token token;
static int line = 1;
static char TokenBuf[20] = {0};

double Parameter=0;		    // 为参数T分配的变量
double Origin_x=0.0, Origin_y=0.0;// 用于记录平移距离
double Rot_ang=0.0;		    // 用于记录旋转角度
double Scale_x=1, Scale_y=1;	    // 用于记录比例因子
HDC    hdc;

static FILE *fp = NULL;
static char * TTP[] = {
    "ORIGIN","SCALE","ROT", "IS",	            // 保留字(一字一码)
    "TO", "STEP", "DRAW","FOR", "FROM",         // 保留字
    "T",				                        // 参数
    ";", "(", ")", ",",                         // 分隔符
    "+", "-", "*", "/", "**",		            // 运算符
    "FUNC",				                        // 函数(调用)
    "NUMBER",			                        // 常数
    "ERRTOKEN",
};

static struct Token TokenTab[18] =
{
	{CONST_ID,	"PI",		3.1415926,	NULL},
	{CONST_ID,	"E",		2.71828,	NULL},

    {T,		    "T",		0.0,		NULL},

    {FUNC,		"SIN",		0.0,		sin},
    {FUNC,		"COS",		0.0,		cos},
    {FUNC,		"TAN",		0.0,		tan},
    {FUNC,		"LN",		0.0,		log},
    {FUNC,		"EXP",		0.0,		exp},
    {FUNC,		"SQRT",		0.0,		sqrt},

    {ORIGIN,	"ORIGIN",	0.0,		NULL},
	{SCALE,		"SCALE",	0.0,		NULL},
	{ROT,		"ROT",		0.0,		NULL},
	{IS,		"IS",		0.0,		NULL},
	{FOR,		"FOR",		0.0,		NULL},
	{FROM,		"FROM",		0.0,		NULL},
	{TO,		"TO",		0.0,		NULL},
	{STEP,		"STEP",		0.0,		NULL},
	{DRAW,		"DRAW",		0.0,		NULL}
};


void PrintToken()
{
    if (fp) {
        rewind(fp);
        TCHAR prtokn[50];
        HANDLE hdlWrite;
        AllocConsole();
        hdlWrite = GetStdHandle(STD_OUTPUT_HANDLE);
        WriteConsole(hdlWrite, TEXT("type        string        value        pointer \n"), 49, NULL, NULL);
        WriteConsole(hdlWrite, TEXT("-----------------------------------------------\n"), 49, NULL, NULL);
        while (1) {
            token = GetToken();  
            if (token.type != NONTOKEN) {
                sprintf(prtokn, "%4d %12s %12f %12p\n", token.type, token.lexeme, token.value, token.Fp);
                WriteConsole(hdlWrite, prtokn, 45, NULL, NULL);
            }
            else break;
        }
        WriteConsole(hdlWrite, TEXT("-----------------------------------------------\n"), 49, NULL, NULL);
        CloseHandle(hdlWrite);
    }
}

void Parser() 
{
    if (fp) {
        rewind(fp);
        FetchToken();	// 获取第一个记号
        Program();		// 递归下降分析
    } 

}

void ExpressionTest()
{
    if (fp) {
        rewind(fp);
        HANDLE hdlWrite;
        AllocConsole();
        hdlWrite = GetStdHandle(STD_OUTPUT_HANDLE);
        struct ExprNode     *x_ptr;
        double x;
        FetchToken();
        while (token.type != NONTOKEN) { 
            x_ptr = Expression(); 
        }
        PrintSyntaxTree(hdlWrite, x_ptr, 0);
    // x = GetExprValue(x_ptr);
    // printf("x = %f ", x);-
        CloseHandle(hdlWrite);
    }

}


void PrintSyntaxTree(HANDLE hdlWrite, struct ExprNode *root, int indent)
{
    char prtokn[10];
    int i = indent; int len = 8;
    while (i-- > 0) {
        WriteConsole(hdlWrite, TEXT("    "), 1, NULL, NULL);
    }
    if (root) {
        switch (root->OpCode) {
            case CONST_ID:
                sprintf(prtokn, " %f\n", root->Content.CaseConst);
                WriteConsole(hdlWrite, prtokn, len, NULL, NULL);
                // printf(" %f\n",root->Content.CaseConst);
                break;
            case T:
                WriteConsole(hdlWrite, TEXT(" T\n"), len, NULL, NULL);
                // printf(" T\n");
                break;
            case FUNC:
                sprintf(prtokn, " %p\n", root->Content.CaseFunc.MathFuncPtr);
                WriteConsole(hdlWrite, prtokn, len, NULL, NULL);
                // printf(" %p\n",root->Content.CaseFunc.MathFuncPtr);
                PrintSyntaxTree(hdlWrite, root->Content.CaseFunc.Child, 1+indent);
                break;
            default:
                WriteConsole(hdlWrite, TTP[root->OpCode], len, NULL, NULL);
                // printf(" %s\n",TTP[root->OpCode]);
                PrintSyntaxTree(hdlWrite, root->Content.CaseOperator.Left, 1+indent);
                PrintSyntaxTree(hdlWrite, root->Content.CaseOperator.Right, 1+indent);
        }
    }
}

int InitScanner(char *fname)
{
    fp = fopen(fname, "r");
    if (fp) { return 1; }
    else { fclose(fp);printf("Open Source File Error ! \n"); return 0; }
}
void CloseScanner()
{
    fclose(fp);
}

static struct Token GetToken()
{
    struct Token token = {ERRTOKEN, NULL, 0.0, NULL};
    token.lexeme = TokenBuf;
    char ch;
    int i=0, j;

    while ((ch = fgetc(fp)) != EOF){                                       
        if (isalpha(ch)) {                                     
            TokenBuf[i++] = toupper(ch);                        
            if (!isalpha(fgetc(fp))) {                         
                if (!feof(fp)) {
                    fseek(fp, -1L, 1);
                }     
                TokenBuf[i] = '\0';
                for (j = 0; j < 18; j++) {                                
                    if (!strcmp(TokenBuf, TokenTab[j].lexeme)){        
                        return TokenTab[j];
                    }
                }
                token.type = T; 
                return token;
            }
            else {
                if (!feof(fp)) {
                    fseek(fp, -1L, 1);
                }   
            }
        }               
        else if (isdigit(ch)) {
            TokenBuf[i++] = ch;
            if (!isdigit(ch=fgetc(fp)) && ch != '.') {             
                if (!feof(fp)) {
                    fseek(fp, -1L, 1);
                }                                                                   
                TokenBuf[i] = '\0';
                token.value = atof(TokenBuf);
                token.type = CONST_ID;
                return token; 
            }
            else {
                if (!feof(fp)) {
                    fseek(fp, -1L, 1);
                }                                                  
            }
        }
        else {
            switch (ch) {
                case ';':                                   
                        token.type      = SEMICO; 
                        TokenBuf[i++]   = ch;     
                        TokenBuf[i]     = '\0';
                        return token;
                case '+': 
                        token.type    = PLUS;
                        TokenBuf[i++] = ch;
                        TokenBuf[i] = '\0';
                        return token;
                case ',': 
                        token.type    = COMMA;
                        TokenBuf[i++]   = ch;
                        TokenBuf[i] = '\0';
                        return token;
                case '(': 
                        token.type    = L_BRACKET;
                        TokenBuf[i++] = ch;
                        TokenBuf[i] = '\0';
                        return token;
                case ')': 
                        token.type    = R_BRACKET; 
                        TokenBuf[i++] = ch;
                        TokenBuf[i] = '\0';
                        return token;
                case '.': 
                        if(isdigit(fgetc(fp)) && isdigit(TokenBuf[i-1])) {
                            fseek(fp, -1L, 1);
                            TokenBuf[i++] = ch;                             
                            break;
                        }
                        else {                                   
                            fseek(fp, -1L, 1);
                            TokenBuf[i++] = ch;
                            TokenBuf[i] = '\0';
                            return token;
                        }
                case '*': 
                        if (fgetc(fp) == '*') {
                            token.type = POWER;
                            TokenBuf[i++] = ch;
                            TokenBuf[i++] = ch;
                            TokenBuf[i] = '\0';
                            return token;
                        }
                        else {
                            if (!feof(fp)) {
                                fseek(fp, -1L, 1);
                            }
                            token.type = MUL;
                            TokenBuf[i++] = ch;
                            TokenBuf[i] = '\0';
                            return token;
                        }

                case '-':   
                        if (fgetc(fp) == '-') {             
                            while ((ch = fgetc(fp)) != '\n' && ch != EOF);
                            line++;
                            break;
                        }
                        else {                      
                            if (!feof(fp)) {
                                fseek(fp, -1L, 1);
                            }
                            token.type = MINUS;                 
                            TokenBuf[i++] = ch;
                            TokenBuf[i] = '\0';
                            return token;
                        }
                case '/':                                   
                        if (fgetc(fp) == '/') {
                            while ((ch = fgetc(fp)) != '\n' && ch != EOF);
                            line++;
                            break;
                        }
                        else {                                 
                            if (!feof(fp)) {
                                fseek(fp, -1L, 1);
                            }
                            token.type = DIV;
                            TokenBuf[i++] = ch;
                            TokenBuf[i] = '\0';
                            return token; 
                        }

                case '\n': line++;
                case '\t':
                case ' ':
                        break;

                default : return token;
            }
        }
    }

    token.type = NONTOKEN;
    return token;
}
static void FetchToken()
{	
    token = GetToken(); 
	if (token.type == ERRTOKEN) SyntaxError(1);

}
static void SyntaxError (int case_of)
{
    printf("[SYNTAXERR]line %d: %4d %12s %12f %12x\n",
            line, token.type, token.lexeme, token.value, token.Fp);
    // exit(1);
}


static void Program()
{      
    while (token.type != NONTOKEN) { 
        Statement(); 
        MatchToken(SEMICO); 
    }
} 
static void Statement(void)
{
    switch (token.type){
        case ORIGIN:
            OriginStatement();
            break;
        case ROT:
            RotStatement();
            break;
        case SCALE:
            ScaleStatement();
            break;
        case FOR:
            ForStatement();
            break;
        default:
            SyntaxError(1);
    }
}
static void MatchToken(enum Token_Type AToken)
{
    if (AToken == token.type) {
        FetchToken();
        // printf("matchtoken %12s\n",token.type==FUNC || token.type==T ?token.lexeme : TTP[token.type]);
    }
    else {
        printf("[ERROR]line %d: expected '%s' before '%s' token.\n", line, TTP[AToken], 
                token.type==FUNC || token.type==T ?token.lexeme : TTP[token.type]);
        FetchToken();
    }
}
static void OriginStatement(void) 
{ 
    struct ExprNode     *x_ptr, *y_ptr;
    double x, y;

    MatchToken (ORIGIN);
    MatchToken (IS);
    MatchToken (L_BRACKET);	    x_ptr = Expression();       //PrintSyntaxTree(x_ptr, 0);
    
    x = GetExprValue(x_ptr); // 获取横坐标的平移值
    MatchToken (COMMA);	        y_ptr = Expression(); 
    y = GetExprValue(y_ptr); // 获取纵坐标的平移值
    
    MatchToken (R_BRACKET); 

    SetOrigin(x, y);	    // 置坐标平移全程量
}
static void RotStatement(void)
{
    double rot;
    struct ExprNode     *r_ptr;

    MatchToken (ROT);
    MatchToken (IS);
    r_ptr = Expression(); rot = GetExprValue(r_ptr);

    SetRot(rot);
}
static void ScaleStatement(void)
{
    double x, y;
    struct ExprNode     *x_ptr, *y_ptr;

    MatchToken (SCALE);
    MatchToken (IS);
    MatchToken (L_BRACKET);	    x_ptr = Expression();

    x = GetExprValue(x_ptr);
    MatchToken (COMMA);	        y_ptr = Expression();
    y = GetExprValue(y_ptr);  

    MatchToken (R_BRACKET);

    SetScale(x, y);
}
static void ForStatement(void) 
{ 
    double Start, End, Step;
    struct ExprNode     *start_ptr, *end_ptr, *step_ptr, 
                        *x_ptr, *y_ptr; 
    MatchToken (FOR);		    MatchToken(T);	
    MatchToken (FROM);	        start_ptr = Expression();

    Start = GetExprValue(start_ptr); 
    MatchToken (TO);		    end_ptr   = Expression(); 
    End = GetExprValue(end_ptr); 
    MatchToken (STEP);	        step_ptr  = Expression(); 
    Step = GetExprValue(step_ptr); 

    MatchToken (DRAW); 
    MatchToken (L_BRACKET);	    x_ptr = Expression();
    MatchToken (COMMA);	        y_ptr = Expression();
    MatchToken (R_BRACKET);

    DrawLoop (Start, End, Step, x_ptr, y_ptr);
}


static struct ExprNode * Expression()
{	
    struct ExprNode *left, *right;
    enum Token_Type token_tmp;
    left = Term();
    while (token.type==PLUS || token.type==MINUS) {
        token_tmp = token.type;
        MatchToken(token_tmp); 
        right = Term();
        left = MakeExprNode(token_tmp,left,right);
    }

    return left;
} 
static struct ExprNode * Term()
{	
    struct ExprNode *left, *right;
    enum Token_Type token_tmp;
    left = Factor();
    while (token.type==MUL || token.type==DIV) { 
        token_tmp = token.type;
        MatchToken(token_tmp);
        right = Factor();
        left = MakeExprNode(token_tmp,left,right);
    }

    return left;
} 
static struct ExprNode * Factor()
{	
    struct ExprNode *left, *right;
    enum Token_Type token_tmp;
    token_tmp = token.type;
    switch (token_tmp) {
        case PLUS:  
            MatchToken(token_tmp);
            left = Factor();
            break;
        case MINUS: 
            left = MakeExprNode(CONST_ID, 0.0);
            MatchToken(token_tmp);
            right = Factor();
            left = MakeExprNode(token_tmp,left,right);
            break;
        default :   
            left = Component();   
    }

    return left;
}
static struct ExprNode *Component()
{	
    struct ExprNode *left, *right;
    enum Token_Type token_tmp;
    left = Atom();
    while (token.type == POWER) {
        token_tmp = token.type;
        MatchToken(token_tmp);
        right =Component();
        left = MakeExprNode(token_tmp,left,right);
    }

    return left;
}
static struct ExprNode *Atom()
{
    struct ExprNode *left;
    FuncPtr fup_tmp = token.Fp;

    switch (token.type) {
        case CONST_ID:
            left = MakeExprNode(CONST_ID,token.value); 
            MatchToken(CONST_ID);
            break;
        case T:
            left = MakeExprNode(T);  
            MatchToken(T);
            break;
        case FUNC:
            MatchToken(FUNC);                  
            MatchToken(L_BRACKET);
            left = Expression();
            left = MakeExprNode(FUNC, fup_tmp, left);
            MatchToken(R_BRACKET);
            break;
        case L_BRACKET:
            MatchToken(L_BRACKET);
            left = Expression();
            MatchToken(R_BRACKET);
            break;
        default:
            printf("[ERROR]line %d: expected %s before '%s' token.\n", line, "Expression", TTP[token.type]);
            return NULL;
            // exit(1);
    }

    return left;
}

static struct ExprNode * MakeExprNode(enum Token_Type opcode, ...)
{ 
    va_list ap;
    va_start(ap, opcode);
    struct ExprNode *ExprPtr = (struct ExprNode *)malloc(sizeof(struct ExprNode));
    ExprPtr->OpCode = opcode;
    
    switch(opcode) 
    {
        case CONST_ID:	// 常数节点
            ExprPtr->Content.CaseConst = (double)va_arg(ap, double);
            break;
        case T:		// 参数节点
            ExprPtr->Content.CaseParmPtr = &Parameter;
            break;
        case FUNC:	       // 函数调用节点
            ExprPtr->Content.CaseFunc.MathFuncPtr = (FuncPtr)va_arg(ap, FuncPtr); 
            ExprPtr->Content.CaseFunc.Child = (struct ExprNode *)va_arg(ap, struct ExprNode *); 
            break;
        default:	       // 二元运算节点
            ExprPtr->Content.CaseOperator.Left = (struct ExprNode *)va_arg(ap, struct ExprNode *);
            ExprPtr->Content.CaseOperator.Right = (struct ExprNode *)va_arg(ap, struct ExprNode *);
            break; 
    }

    va_end(ap);
    return ExprPtr;
}

static double GetExprValue(struct ExprNode * root)
{
    if (root) {
        switch (root -> OpCode) { 
            case PLUS  :
	            return GetExprValue(root->Content.CaseOperator.Left ) 
                        + GetExprValue(root->Content.CaseOperator.Right);
            case MINUS : 	
                return GetExprValue(root->Content.CaseOperator.Left ) 
                        - GetExprValue(root->Content.CaseOperator.Right);
            case MUL : 	
                return GetExprValue(root->Content.CaseOperator.Left ) 
                        * GetExprValue(root->Content.CaseOperator.Right);
            case DIV : 	
                return GetExprValue(root->Content.CaseOperator.Left ) 
                        / GetExprValue(root->Content.CaseOperator.Right);
            case POWER : 	
                return pow( GetExprValue(root->Content.CaseOperator.Left),  
                        GetExprValue(root->Content.CaseOperator.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 ;
        }
    }
    return 0.0;
}

static void CalcCoord(struct ExprNode *x_nptr, struct ExprNode *y_nptr, double *x_val, double *y_val)
{
    double local_x, local_y, temp;
    local_x =   GetExprValue(x_nptr); 	// 计算点的原始坐标
    local_y =   GetExprValue(y_nptr);                                       //printf("\nori%f,%f\n", local_x, local_y);
    local_x *=  Scale_x; 			// 比例变换
    local_y *=  Scale_y;		                                            //printf("\nsca%f,%f\n", local_x, local_y);
    temp    =   local_x*cos(Rot_ang)+local_y*sin(Rot_ang);
    local_y =   local_y*cos(Rot_ang)-local_x*sin(Rot_ang);                  //printf("\nrot%f\n", Rot_ang);
    local_x =   temp; 			// 旋转变换
    local_x +=  Origin_x;			// 平移变换
    local_y +=  Origin_y;	
    *x_val  =   local_x; 			// 返回变换后点的坐标
    *y_val  =   local_y; 

}
static void DrawPixel(unsigned long x, unsigned long y)
{
    // printf("\ndraw%u,%u\n", x, y);
    SetPixel(hdc, x, y, RGB(0, 0, 255));
}

static void DrawLoop(double Start, double End, double Step, struct ExprNode *HorPtr, struct ExprNode *VerPtr)
{
    double x, y;
    for (Parameter=Start; Parameter<=End; Parameter+=Step) {
        CalcCoord(HorPtr, VerPtr, &x, &y);                    // 计算实际坐标
        DrawPixel((unsigned long)x, (unsigned long)y);      // 根据坐标绘制点
    }

}
static void SetOrigin(double x, double y)
{
    Origin_x = x;
    Origin_y = y; 
}
static void SetScale(double x, double y)
{
    Scale_x = x;
    Scale_y = y;
}
static void SetRot(double r)
{
    Rot_ang = r;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    RECT        rect;

    switch (message){
        case WM_PAINT:
            hdc = BeginPaint (hwnd, &ps) ;
            GetClientRect (hwnd, &rect) ;
            // Rectangle(hdc,10,10,100,100);
            // MessageBox(hwnd, TEXT("you need to drag txtfile on this program."),TEXT("Usage"),MB_OK | MB_ICONWARNING);
            Parser(); 
            EndPaint (hwnd, &ps) ;
            break;
        case WM_DESTROY: 
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam) ;
    }
    return 0;
}

void help(void)
{
    int len = 58;
    HANDLE hdlWrite;
    AllocConsole();
    hdlWrite = GetStdHandle(STD_OUTPUT_HANDLE);
    WriteConsole(hdlWrite, TEXT("*******************************************************\n"),len, NULL, NULL);
    WriteConsole(hdlWrite, TEXT(" Usage : draw filename.txt [-w|-s]                     \n"),len, NULL, NULL);
    WriteConsole(hdlWrite, TEXT("         OR  drag txtfile on this program directly     \n\n"),len, NULL, NULL);
    WriteConsole(hdlWrite, TEXT("     -w: Scan and Print tokens.                        \n"),len, NULL, NULL);
    WriteConsole(hdlWrite, TEXT("     -s: Print Syntax Tree                             \n"),len, NULL, NULL);
    WriteConsole(hdlWrite, TEXT("default: draw your image.                              \n"),len, NULL, NULL);
    WriteConsole(hdlWrite, TEXT("\n******************************************************\n"),len, NULL, NULL);
    CloseHandle(hdlWrite);
}

头文件

#ifndef CMPL_H
#define CMPL_H

#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <stdarg.h>
#include <stdlib.h>

typedef double (* FuncPtr)(double);

enum Token_Type			                        // 记号的类别,共22个
{	
    ORIGIN, SCALE, ROT, IS,	                    // 保留字(一字一码)
    TO, STEP, DRAW,FOR, FROM,                   // 保留字
    T,				                            // 参数
    SEMICO, L_BRACKET, R_BRACKET, COMMA,        // 分隔符
    PLUS, MINUS, MUL, DIV, POWER,		        // 运算符
    FUNC,				                        // 函数(调用)
    CONST_ID,			                        // 常数
    ERRTOKEN,			                        // 出错记号(非法输入)    
    NONTOKEN,			                        // 空记号(源程序结束)
}; 
struct Token		                                // 记号的数据结构
{	
    enum Token_Type     type;	                    // 类别
	char                * lexeme;	                // 属性,原始输入的字符串
	double              value;		                // 属性,若记号是常数则是常数的值
	FuncPtr             Fp;			                // 属性,若记号是函数则是函数指针
}; 
struct ExprNode 
{  
    enum Token_Type OpCode;	// 记号种类
    union {
        struct { 
            struct ExprNode *Left, *Right; 
            } CaseOperator;	// 二元运算

        struct { 
            struct ExprNode * Child; 
 	        FuncPtr MathFuncPtr; 
            } CaseFunc;	// 函数调用

        double CaseConst; 	// 常数,绑定右值

        double * CaseParmPtr; // 参数T,绑定左值
    }Content;
    
}; 

int InitScanner(char *fname);
static struct Token GetToken();
void CloseScanner();
void PrintToken(void);

static struct ExprNode * Expression();
static struct ExprNode * Term();
static struct ExprNode * Factor();
static struct ExprNode * Component();
static struct ExprNode * Atom(); 

void Parser(void);
void PrintSyntaxTree(HANDLE hdlWrite, struct ExprNode *root, int indent);
static void Program();

static void Statement();
static void OriginStatement();
static void RotStatement();
static void ScaleStatement();
static void ForStatement();

static void SyntaxError (int case_of);
static void MatchToken(enum Token_Type AToken);
static void FetchToken();
static struct ExprNode * MakeExprNode(enum Token_Type opcode, ...);
void ExpressionTest(void);

static void SetRot(double r);
static void SetScale(double x, double y);
static void SetOrigin(double x, double y);
static void DrawLoop(double Start, double End, double Step, struct ExprNode *HorPtr, struct ExprNode *VerPtr);
static void DrawPixel(unsigned long x, unsigned long y);
static void CalcCoord(struct ExprNode *x_nptr, struct ExprNode *y_nptr, double *x_val, double *y_val);
static double GetExprValue(struct ExprNode * root);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void help(void);
#endif

测试用例

滑稽

// Manual:
// 循环绘图(FOR-DRAW)		左上角为原点
// 比例设置(SCALE)			x方向从左向右增长
// 角度旋转(ROT)				y方向从上到下增长(与一般的坐标系方向相反)
// 坐标平移(ORIGIN)
// 支持函数  SIN		sin
//			 COS		cos
//    		 TAN        tan
//			 LN		    log
//			 EXP		exp
//			 SQRT	    sqrt
// 运算符	 +	-	*	/	**		//a ** b = pow(a, b)
// 注释        (-- 或 //)
// 默认值:
// 	origin is (0, 0)
// 	rot is 0;
// 	scale is (1, 1)
// 	
-----------------------------------------------------------------------
// 函数绘图源程序举例 
// --------------- 函数f(t)=t的图形
// origin is (100, 300);	-- 设置原点的偏移量
// rot is 0;			-- 设置旋转角度(不旋转)
// scale is (1, 1);		-- 设置横坐标和纵坐标的比例
// for T from 0 to 200 step 1 draw (t, 0);
// 				-- 横坐标的轨迹(纵坐标为0)
// for T from 0 to 150 step 1 draw (0, -t);
// 				-- 纵坐标的轨迹(横坐标为0)
// for T from 0 to 120 step 1 draw (t, -t);
// 				-- 函数f(t)=t的轨迹 
// 				
------------------------------------------------------------------------
// 1.循环绘图(FOR-DRAW )语句 
// 语法:FOR T FROM 起点 TO 终点 STEP 步长 DRAW(横坐标, 纵坐标);
// 语义:令T从起点到终点、每次改变一个步长,绘制出由(横坐标,纵坐标)所规定的点的轨迹。
// 举例:FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (cos(T), sin(T));
// 说明:该语句的作用是令T从0到2*PI、步长 PI/50,绘制出各个点的坐标(cos(T),sin(T)),即一个单位圆。
// 
// 注意:
// 由于绘图系统的默认值是
// 	ORIGIN IS (0,0);
// 	ROT IS 0;
// 	SCALE IS (1, 1);
// 所以实际绘制出的图形是在屏幕左上角的一个点。
// 
// 2.比例设置(SCALE)语句
// 语法:SCALE IS (横坐标比例因子,纵坐标比例因子);
// 语义:设置横坐标和纵坐标的比例,并分别按照比例因子进行缩放。
// 举例:SCALE IS (100, 100);
// 说明:将横坐标和纵坐标的比例设置为1:1,且放大100倍。
// 	  若: SCALE IS (100, 100/3); 
// 	  则:横坐标和纵坐标的比例为3:1。
// 
// 3.坐标平移(ORIGIN)语句
// 语法:ORIGIN IS (横坐标,纵坐标); 
// 语义:将坐标系的原点平移到横坐标和纵坐标规定的点处。
// 举例:ORIGIN IS (360, 240); 
// 说明:将原点从(0, 0)平移到(360, 240) 处。
// 
// 4.角度旋转(ROT)语句
// 语法:ROT  IS 角度; 
// 语义:逆时针旋转角度所规定的弧度值。
// 举例:ROT IS PI/2;  
// 说明:逆时针旋转PI/2,即逆时针旋转90度。
// 5. 注释语句 
// 注释的作用:便于理解;屏蔽暂时不需要的语句。
// 语法://  This is a comment line 
// 	  --  此行是注释 
// 	  
// 语义:// 或 -- 之后,直到行尾,均是注释
----------------------------------------------------------------
// 运行方法:将此txt文件拖到draw.exe 上即可运行。


//origin is (450, 350);
//scale is (50, 50);
//for t from 0 to 2*pi step pi/100 draw(cos(t), sin(t));
//scale is (100, 100);
//for t from 0 to 2*pi step pi/200 draw(cos(t), sin(t));

//scale is (10, 10);
//for t from -10 to 10 step 0.001 draw(t, sin(t));
//for t from -10 to 10 step 0.001 draw(sin(t), t);

//origin is (450, 350);	-- 设置原点的偏移量
//rot is pi/6;			-- 设置旋转角度
//scale is (2, 1);		-- 设置横、纵坐标比例
//for t from -100 to 100 step 1 draw (t, 0);	-- 横坐标
//for t from -100 to 100 step 1 draw (0, t);	-- 纵坐标
//scale is (200, 100);	-- 设置横、纵坐标比例
//for t from 0 to 2*pi step pi/50 draw (cos(t),sin(t));

----------------------------------------------------------------------
origin is (450,350);
scale is (200,200);
for t from 0 to 2*pi step pi/500 draw(cos(t), sin(t));

origin is (450,350);
scale is (150,150);
for t from pi/12 to 11*pi/12 step pi/500 draw(cos(t), sin(t));

origin is (330,350);
scale is (100,100);
for t from pi/4+pi to 3*pi/4+pi step pi/500 draw(cos(t), sin(t));
scale is (100-20*sqrt(2),100-20*sqrt(2));
for t from pi/4+pi to 3*pi/4+pi step pi/500 draw(cos(t), sin(t));

origin is (570,350);
scale is (100,100);
for t from pi/4+pi to 3*pi/4+pi step pi/500 draw(cos(t), sin(t));
scale is (100-20*sqrt(2),100-20*sqrt(2));
for t from pi/4+pi to 3*pi/4+pi step pi/500 draw(cos(t), sin(t));

origin is (320+50*sqrt(2),360-50*sqrt(2));
scale is (10*sqrt(2),10*sqrt(2));
for t from -pi/4 to 3*pi/4 step pi/500 draw(cos(t), sin(t));
origin is (560+50*sqrt(2),360-50*sqrt(2));
scale is (10*sqrt(2),10*sqrt(2));
for t from -pi/4 to 3*pi/4 step pi/500 draw(cos(t), sin(t));


origin is (340-50*sqrt(2),360-50*sqrt(2));
scale is (10*sqrt(2),10*sqrt(2));
for t from pi/4 to 5*pi/4 step pi/500 draw(cos(t), sin(t));
origin is (580-50*sqrt(2),360-50*sqrt(2));
scale is (10*sqrt(2),10*sqrt(2));
for t from pi/4 to 5*pi/4 step pi/500 draw(cos(t), sin(t));


origin is (330-(100-10*sqrt(2))/2,350-(100-10*sqrt(2))/2*sqrt(3));
scale is (10*sqrt(2),10*sqrt(2));
for t from 0 to 2*pi step pi/500 draw(cos(t), sin(t));
origin is (570-(100-10*sqrt(2))/2,350-(100-10*sqrt(2))/2*sqrt(3));
scale is (10*sqrt(2),10*sqrt(2));
for t from 0 to 2*pi step pi/500 draw(cos(t), sin(t));

origin is (315,350);
scale is (50,20);
for t from 0 to 2*pi step pi/500 draw(cos(t), sin(t));
origin is (585,350);
for t from 0 to 2*pi step pi/500 draw(cos(t), sin(t));

origin is (455-100*sqrt(2),370-100*sqrt(2));
scale is (30,30);
rot is	3*pi/4;
for t from 0 to 3*pi/4 step pi/500 draw(cos(t), sin(t));
origin is (445+100*sqrt(2),370-100*sqrt(2));
scale is (30,30);
rot is	pi;
for t from 0 to 3*pi/4 step pi/500 draw(cos(t), sin(t));

测试用例

说明

链接:代码及程序(windows平台)
提取码:0soo
下载后直接将README.txt拖到draw_0_3.exe即可运行。

课程作业,未优化,未完成,代码稀烂,仅作记录

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值