• 用C++编写简单绘图语言的语法分析器——程序清单


     1//-----------------------------parser.h---------------------------------
     2#ifndef PARSER_H
     3#define PARSER_H
     4
     5#include "scanner.h"
     6
     7typedef double (*FuncPtr)(double);
     8struct ExprNode        // 语法树节点类型
     9{
    10    enum Token_Type OpCode;
    11    union
    12    {
    13        struct 
    14        
    15            ExprNode *Left, *Right; 
    16        }
     CaseOperator;
    17        struct 
    18        
    19            ExprNode *Child; 
    20            FuncPtr MathFuncPtr; 
    21        }
     CaseFunc;
    22        double CaseConst;
    23        double *CaseParmPtr;
    24    }
     Content;
    25}
    ;
    26
    27extern void Parser(char *SrcFilePtr);        // 语法分析器对外的接口
    28
    29#endif
      1//-------------------------parser.cpp-----------------------------
      2
      3#include "parser.h"
      4
      5#define PARSER_DEBUG
      6
      7#ifndef PARSER_DEBUG
      8    #include "semantic.h"
      9#endif
     10
     11#ifdef PARSER_DEBUG
     12    #define enter(x) printf("enter in "); printf(x); printf("\n")
     13#else
     14    #define enter(x)
     15#endif
     16
     17#ifdef PARSER_DEBUG
     18    #define back(x) printf("exit from "); printf(x); printf("\n")
     19#else
     20    #define back(x)
     21#endif
     22
     23#ifdef PARSER_DERBUG
     24    #define call_match(x) printf("match token "); printf(x); printf("\n")
     25#else
     26    #define call_match(x)
     27#endif
     28
     29#ifdef PARSER_DEBUG
     30    #define Tree_trace(x) PrintSyntaxTree(x, 1);
     31#else
     32    #define Tree_trace
     33#endif
     34
     35#ifdef PARSER_DEBUG
     36    double Parameter = 0;            //参数T的存储空间
     37#else
     38    double Parameter = 0,            //参数存储空间
     39    Origin_x = 0, Origin_y = 0,        //横纵坐标平移距离
     40    Scale_x = 1,Scale_y = 1,        //横纵比例因子
     41    Rot_angle = 0;                    //旋转角度
     42#endif
     43
     44static Token token;                    //记号
     45
     46
     47// ------------辅助函数声明
     48static void FetchToken();
     49static void MatchToken(enum Token_Type AToken);
     50static void SyntaxError(int case_of);
     51static void ErrMsg(unsigned LineNo, char *descrip, char *string);
     52static void PrintSyntaxTree(struct ExprNode *root, int indent);
     53
     54// ------------非终结符的递归子程序声明
     55static void Program();
     56static void Statement();
     57static void OriginStatement();
     58static void RotStatement();
     59static void ScaleStatement();
     60static void ForStatement();
     61static struct ExprNode *Expression();
     62static struct ExprNode *Term();
     63static struct ExprNode *Factor();
     64static struct ExprNode *Component();
     65static struct ExprNode *Atom();
     66
     67// -------------外部接口与语法树构造函数声明
     68extern void Parser(char *SrcFilePtr);
     69static struct ExprNode *MakeExprNode(enum Token_Type opcode, );
     70
     71// -------------通过词法分析器接口GetToken获取一个记号
     72static void FetchToken()
     73{
     74    token = GetToken();
     75    if(token.type == ERRTOKEN) SyntaxError(1);
     76}

     77
     78// -------------匹配记号
     79static void MatchToken(enum Token_Type The_Token)
     80{
     81    if(token.type != The_Token) SyntaxError(2);
     82    FetchToken();
     83}

     84
     85// -------------语法错误处理
     86static void SyntaxError(int case_of)
     87{
     88    switch(case_of)
     89    {
     90    case 1: ErrMsg(LineNo, "错误记号", token.lexeme);
     91        break;
     92    case 2: ErrMsg(LineNo, "不是预期记号", token.lexeme);
     93        break;
     94    }

     95}

     96
     97// -------------打印错误信息
     98void ErrMsg(unsigned int LineNo, char *descrip, char *string)
     99{
    100#ifdef PARSER_DEBUG
    101    printf("Line No %5d:%s %s !\n", LineNo, descrip, string);
    102#else
    103    char msg[256];
    104    memset(msg, 0256);
    105    sprintf("Line No %5d:%s %s !\n", LineNo, descrip, string);
    106#endif
    107
    108#ifdef _VC_COMPILER
    109    MessageBox(NULL,msg"error!",MB_OK);
    110#endif
    111
    112#ifdef _BC_COMPILER
    113    printf("%s\n",msg);
    114#endif
    115
    116    CloseScanner();
    117    exit(1);
    118}

    119
    120// -------------先序遍历并打印表达式的语法树
    121void PrintSyntaxTree(struct ExprNode *root, int indent)
    122{
    123    int temp;
    124    for(temp = 1; temp <= indent; ++temp) printf("\t");        // 缩进
    125    switch(root->OpCode)
    126    {
    127    case PLUS :        printf("%s\n""+");break;
    128    case MINUS :    printf("%s\n""-");break;
    129    case MUL :        printf("%s\n""*");break;
    130    case DIV :        printf("%s\n""/");break;
    131    case POWER :    printf("%s\n""**");break;
    132    case FUNC :        printf("%x\n", root->Content.CaseFunc.MathFuncPtr);break;
    133    case CONST_ID :    printf("%f\n", root->Content.CaseConst);break;
    134    case T:            printf("%s\n""T");break;
    135    default:        printf("Error Tree Node!\n");exit(0);
    136    }

    137    if(root->OpCode == CONST_ID || root->OpCode == T)    //叶子节点返回
    138        return;
    139    if(root->OpCode == FUNC)                            //递归打印一个孩子的节点
    140        PrintSyntaxTree(root->Content.CaseFunc.Child, indent+1);
    141    else                                                //递归打印两个孩子的节点
    142    {
    143        PrintSyntaxTree(root->Content.CaseOperator.Left, indent+1);
    144        PrintSyntaxTree(root->Content.CaseOperator.Right, indent+1);
    145    }

    146}

    147
    148// -------------绘图语言解释器入口(与主程序的外部接口)
    149void Parser(char *SrcFilePtr)
    150{
    151    enter("Parser");
    152    if(!InitScanner(SrcFilePtr))                        //初始化词法分析器
    153    {
    154        printf("Open Source File Error!\n"); 
    155        return;
    156    }

    157    FetchToken();                                        //获取第一个记号
    158    Program();                                            //递归下降分析
    159    CloseScanner();                                        //关闭词法分析器
    160    back("Parser");
    161    return;
    162}

    163
    164// -------------Program的递归子程序
    165static void Program()
    166{
    167    enter("Program");
    168    while(token.type != NONTOKEN)
    169    {
    170        Statement();
    171        MatchToken(SEMICO);
    172    }

    173    back("Program");
    174}

    175
    176// --------------Statement的递归子程序
    177static void Statement()
    178{
    179    enter("Statement");
    180    switch(token.type)
    181    {
    182    case ORIGIN :    OriginStatement();    break;
    183    case SCALE    :    ScaleStatement();    break;
    184    case ROT    :    RotStatement();        break;
    185    case FOR    :    ForStatement();        break;
    186    default        :    SyntaxError(2);        break;
    187    }

    188    back("Statement");
    189}

    190
    191// -------------OriginStatement的递归子程序
    192static void OriginStatement(void)
    193{
    194    struct ExprNode *tmp;
    195
    196    enter("OriginStatement");
    197    MatchToken(ORIGIN);
    198    MatchToken(IS);
    199    MatchToken(L_BRACKET);
    200    tmp = Expression();
    201
    202#ifndef PARSER_DEBUG
    203    Origin_x = GetExprValue(tmp);                // 获取横坐标的平移距离
    204    DelExprTree(tmp);
    205#endif
    206
    207    MatchToken(COMMA);
    208    tmp = Expression();
    209
    210#ifndef PARSER_DEBUG
    211    Origin_y = GetExprValue(tmp);                // 获取纵坐标的平移距离
    212    DelExprTree(tmp);
    213#endif
    214
    215    MatchToken(R_BRACKET);
    216    back("OriginStatement");
    217}

    218
    219// -------------ScaleStatement的递归子程序
    220static void ScaleStatement(void)
    221{
    222    struct ExprNode *tmp;
    223
    224    enter("ScaleStatement");
    225    MatchToken(SCALE);
    226    MatchToken(IS);
    227    MatchToken(L_BRACKET);
    228    tmp = Expression();
    229
    230#ifndef PARSER_DEBUG
    231    Scale_x = GetExprValue(tmp);                //获取横坐标的比例因子
    232    DelExprTree(tmp);
    233#endif
    234
    235    MatchToken(COMMA);
    236    tmp = Expression();
    237
    238#ifndef PARSER_DEBUG
    239    Scale_y = GetExprValue(tmp);                //获取纵坐标的比例因子
    240    DelExprTree(tmp);
    241#endif
    242
    243    MatchToken(R_BRACKET);
    244    back("ScaleStatement");
    245}

    246
    247// -------------RotStatement的递归子程序
    248static void RotStatement(void)
    249{
    250    struct ExprNode *tmp;
    251
    252    enter("RotStatement");
    253    MatchToken(ROT);
    254    MatchToken(IS);
    255    tmp = Expression();
    256
    257#ifndef PARSER_DEBUG
    258    Rot_angle = GetExprValue(tmp);                //获取旋转角度
    259    DelExprTree(tmp);
    260#endif
    261
    262    back("RotStatement");
    263}

    264
    265// -------------ForStatement的递归子程序
    266static void ForStatement(void)
    267{
    268
    269#ifndef PARSER_DEBUG
    270    double Start, End, Step;                    //绘图起点, 终点, 步长
    271#endif
    272
    273    struct ExprNode *start_ptr, *end_ptr, *step_ptr, *x_ptr, *y_ptr;    
    274                                                //各表达式语法树根节点指针
    275
    276    enter("ForStatement");
    277
    278    MatchToken(FOR);    call_match("FOR");
    279    MatchToken(T);        call_match("T");
    280    MatchToken(FROM);    call_match("FROM");
    281
    282    start_ptr = Expression();                    //构造参数起点表达式语法树
    283
    284#ifndef PARSER_DEBUG
    285    Start = GetExprValue(start_ptr);            //计算参数起点表达式的值
    286    DelExprTree(start_ptr);                        //释放参数起点语法树所占空间
    287#endif
    288
    289    MatchToken(TO);        call_match("TO");
    290    end_ptr = Expression();                        //构造参数终点表达式语法树
    291
    292#ifndef PARSER_DEBUG
    293    End = GetExprValue(end_ptr);                //计算参数终点表达式
    294    DelExprTree(end_ptr);                        //释放参数终点语法树所占空间
    295#endif
    296
    297    MatchToken(STEP);    call_match("STEP");
    298    step_ptr = Expression();                    //构造参数步长表达式语法树
    299
    300#ifndef PARSER_DEBUG
    301    Step = GetExprValue(step_ptr);                //计算参数步长表达式值
    302    DelExprTree(step_ptr);                        //释放参数步长语法树所占空间
    303#endif
    304
    305    MatchToken(DRAW);    call_match("DRAW");
    306    MatchToken(L_BRACKET);    call_match("(");
    307    x_ptr = Expression();                        //构造横坐标表达式语法树
    308    MatchToken(COMMA);    call_match(",");
    309    y_ptr = Expression();                        //构造纵坐标表达式语法树
    310    MatchToken(R_BRACKET);    call_match(")");
    311
    312#ifndef PARSER_DEBUG
    313    DrawLoop(Start, End, Step, x_ptr, y_ptr);    //绘制图形
    314    DelExprTree(x_ptr);                            //释放横坐标语法树所占空间
    315    DelExprTree(y_ptr);                            //释放纵坐标语法树所占空间
    316#endif
    317
    318    back("ForStatement");
    319}

    320
    321// -------------Expression的递归子程序
    322static struct ExprNode * Expression()
    323{
    324    struct ExprNode *left, *right;                //左右子树节点的指针
    325    Token_Type token_tmp;                        //当前记号
    326
    327    enter("Expression");
    328    left = Term();                                //分析左操作数且得到其语法树
    329    while(token.type == PLUS || token.type == MINUS)
    330    {
    331        token_tmp = token.type;
    332        MatchToken(token_tmp);
    333        right = Term();                            //分析右操作数且得到其语法树
    334        left = MakeExprNode(token_tmp, left, right);    
    335                                                //构造运算的语法树, 结果为左子树
    336    }

    337    Tree_trace(left);                            //打印表达式的语法树
    338    back("Expression");
    339    return left;                                //返回最终表达式的语法树
    340}

    341
    342// -------------Term的递归子程序
    343static struct ExprNode *Term()
    344{
    345    struct ExprNode *left, *right;
    346    Token_Type token_tmp;
    347
    348    left = Factor();
    349    while(token.type == MUL || token.type == DIV)
    350    {
    351        token_tmp = token.type;
    352        MatchToken(token_tmp);
    353        right = Factor();
    354        left = MakeExprNode(token_tmp, left, right);
    355    }

    356    return left;
    357}

    358
    359// -------------Factor的递归子程序
    360static struct ExprNode * Factor()
    361{
    362    struct ExprNode *left, *right;
    363
    364    if(token.type == PLUS)                        //匹配一元加运算
    365    {
    366        MatchToken(PLUS);
    367        right = Factor();                        //表达式退化为仅有右操作数的表达式
    368    }

    369    else if(token.type == MINUS)                //匹配一元减运算
    370    {
    371        MatchToken(MINUS);                        //表达式转化为二元减运算的表达式
    372        right = Factor();
    373        left = new ExprNode;
    374        left->OpCode = CONST_ID;
    375        left->Content.CaseConst = 0.0;
    376        right = MakeExprNode(MINUS, left, right);
    377    }

    378    else right = Component();                    //匹配非终结符Component
    379
    380    return right;
    381}

    382
    383// -------------Comoenent的递归子程序
    384static struct ExprNode *Component()
    385{
    386    struct ExprNode *left, *right;
    387
    388    left = Atom();
    389    if(token.type == POWER)
    390    {
    391        MatchToken(POWER);
    392        right = Component();                    //递归调用Component以实现POWER的右集合
    393        left = MakeExprNode(POWER, left, right);
    394    }

    395    return left;
    396}

    397
    398// -------------Atom的递归子程序
    399static struct ExprNode *Atom()
    400{
    401    struct Token t = token;
    402    struct ExprNode *address, *tmp;
    403
    404    switch(token.type)
    405    {
    406    case CONST_ID :
    407        MatchToken(CONST_ID);
    408        address = MakeExprNode(CONST_ID, t.value);
    409        break;
    410    case T :
    411        MatchToken(T);
    412        address = MakeExprNode(T);
    413        break;
    414    case FUNC :
    415        MatchToken(FUNC);
    416        MatchToken(L_BRACKET);
    417        tmp = Expression();
    418        address = MakeExprNode(FUNC, t.FuncPtr, tmp);
    419        MatchToken(R_BRACKET);
    420        break;
    421    case L_BRACKET :
    422        MatchToken(L_BRACKET);
    423        address = Expression();
    424        MatchToken(R_BRACKET);
    425        break;
    426    default :
    427        SyntaxError(2);
    428    }

    429    return address;
    430}

    431
    432
    433// -------------生成语法树的一个结点
    434static struct ExprNode *MakeExprNode(enum Token_Type opcode, )
    435{
    436    struct ExprNode *ExprPtr = new (struct ExprNode);
    437    ExprPtr->OpCode = opcode;                    //接收记号的种类
    438    va_list ArgPtr;
    439    va_start(ArgPtr, opcode);
    440    switch(opcode)                                //根据记号的类别构造不同的节点
    441    {
    442    case CONST_ID :                                //常数节点
    443        ExprPtr->Content.CaseConst = (double)va_arg(ArgPtr, double);
    444        break;
    445    case T :                                    //参数节点
    446        ExprPtr->Content.CaseParmPtr = &Parameter;
    447        break;
    448    case FUNC :                                    //函数调用节点
    449        ExprPtr->Content.CaseFunc.MathFuncPtr = (FuncPtr)va_arg(ArgPtr, FuncPtr);
    450        ExprPtr->Content.CaseFunc.Child = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);
    451        break;
    452    default :
    453        ExprPtr->Content.CaseOperator.Left = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);
    454        ExprPtr->Content.CaseOperator.Right = (struct ExprNode *)va_arg(ArgPtr, struct ExprNode *);
    455        break;
    456    }

    457    va_end(ArgPtr);
    458
    459    return ExprPtr;
    460}

     1//----------------------------parsermain.cpp-----------------------
     2
     3#include <stdio.h>
     4#include "parser.h"
     5
     6extern void Parser(char *SrcFilePtr);
     7
     8int main()
     9{
    10    Parser("test.txt");
    11    return 0;
    12}

    注:要想正常运行需要把词法分析器的那部分也加入到工程中
  • 相关阅读:
    BZOJ 5297: [Cqoi2018]社交网络 矩阵树定理
    BZOJ 5300: [Cqoi2018]九连环 打表+FFT
    BZOJ 5298: [Cqoi2018]交错序列 二项式定理+矩阵乘法
    BZOJ 5301: [Cqoi2018]异或序列 莫队+桶
    BZOJ 5324: [Jxoi2018]守卫 区间DP
    BZOJ 5322: [Jxoi2018]排序问题 模拟+贪心
    点斜式
    斜截式
    斜率
    求线段的交点
  • 原文地址:https://www.cnblogs.com/suyang/p/1171195.html
Copyright © 2020-2023  润新知