zoukankan      html  css  js  c++  java
  • 编译原理实验3

    @

    实验三: Tiny扩充语言的语法分析

    一、实验内容:

    扩充的语法规则有:实现 while、do while、for、if语句、+= 加法赋值运算符号(类似于C语言的+=)、
    求余%、乘方^、<=(小于等于)、<>(不等于)运算符号,具体文法规则自行构造。

    可参考:云盘中参考书P97及P136的文法规则。

    (1) While-stmt --> while(exp) stmt-sequence endwhile
    (2) Dowhile-stmt-->do stmt-sequence while(exp);
    (3) for-stmt-->for identifier:=simple-exp to simple-exp do stmt-sequence enddo 步长递增1
    (4) for-stmt-->for identifier:=simple-exp downto simple-exp do stmt-sequence enddo 步长递减1
    (5) += 加法赋值运算符号、求余%、乘方^、<=(小于等于)、<>(不等于)运算符号的文法规则请自行组织。
    (6) 把TINY语言原有的if语句书写格式
    if_stmt-->if exp then stmt-sequence end | | if exp then stmt-sequence else stmt-sequence end
    改写为:
    if_stmt-->if(exp) stmt-sequence else stmt-sequence | if(exp) stmt-sequence
    (7)为了实现以上的扩充或改写功能,还需要对原tiny语言的文法规则做如何的处理?

    二、要求:
    (1)要提供一个源程序编辑界面,以让用户输入源程序(可保存、打开源程序)
    (2)可由用户选择是否生成语法树,并可查看所生成的语法树。
    (3)应该书写完善的软件文档

    三、完成时间:四周(第9周-第13周)

    四、上交方法:
    由各班班长或学习委员将每个同学的实验源程序、可执行程序、测试用例、文档刻录成光盘。

    五、完成方式:每个学生自行独立完成。

    六、测试数据

    测试文件1:

    { Sample program
    in TINY language -
    computes factorial
    }
    read x; { input an integer }
    if (0<x) { don't compute if x <= 0 }
    fact := 1;
    do
    fact := fact * x;
    x := x - 1
    while ( 0<x );
    write fact; { output factorial of x }

    测试文件2:

    { Sample program
    in TINY language -
    computes factorial
    }
    read x; { input an integer }
    if ( 0<x ) { don't compute if x <= 0 }
    for fact := x downto 1 do
    fact := fact * x;
    enddo
    write fact; { output factorial of x }

    测试文件3:

    { Sample program
    in TINY language -
    computes factorial
    }
    read x; { input an integer }
    if ( 0<x ) { don't compute if x <= 0 }
    fact := 1;
    while(0<x)
    fact := fact * x;
    x := x - 1
    endwhile
    write fact; { output factorial of x }

    为了做好全面的测试,你还需要增加相应的测试文件。

    任务

    扩充文法规则

    更改前:

    program -> stmt-sequence
    stmt-sequence -> statement { ; statement }
    statement -> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt
    if-stmt -> if exp then stmt-sequence[else stmt-sequence] end
    repeat-stmt -> repeat stmt-sequence until exp
    assign-stmt -> identifier := exp
    read-stmt -> read identifier
    write-stmt -> write exp
    exp -> simple-exp[comparison-op simple-exp]
    comparison-op -> < | =
    simple-exp -> term {addop term}
    addop -> + | -
    term -> factor {mulop factor}
    mulop -> * | /
    factor -> (exp) | number | identifier
    

    更改后:

    program -> stmt-sequence
    stmt-sequence -> statement { ; statement }
    statement -> if-stmt | repeat-stmt | assign-stmt | read-stmt | write-stmt | While-stmt | Dowhile-stmt | for-stmt
    if-stmt -> if(exp)stmt-sequence[else stmt-sequence]
    repeat-stmt -> repeat stmt-sequence until exp
    assign-stmt -> identifier assignop exp
    assignop -> [:= | +=]
    read-stmt -> read identifier
    write-stmt -> write exp
    While-stmt -> while(exp) stmt-sequence endwhile
    Dowhile-stmt -> do stmt-sequence while(exp)
    for-stmt -> for identifier:=simple-exp [to | downto] simple-exp do stmt-sequence enddo
    exp -> simple-exp[comparison-op simple-exp]
    comparison-op -> < | = | <= | <>
    simple-exp -> term {addop term}
    addop -> + | -
    term -> factor {mulop factor}
    mulop -> * | / | %
    factor -> powernum {powerop powernum}
    powerop -> ^
    powernum -> (exp) | number | identifier
    

    改写对应parse代码

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <string.h>
    using namespace std;
    
    /*********************************************************
    创建核心类Core,功能为:
    (1) 类中拥有属性fileString,并且该fileString内容
    可以被更改
    (2) char getNextChar(); 读取fileString中的字符
    (3) Token getToken(); 返回Token对象(tokenType, tokenString)
    (4) TreeNode * parse(); 返回一棵语法树
    (5) string treeStr(); 将语法树以字符串的形式呈现
    *********************************************************/
    
    #define MAXRESERVED 15
    #define TRUE 1
    #define FALSE 0
    
    enum TokenType
    /* book-keeping tokens */
    {ENDFILE,ERROR,
    /* reserved words */
    IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,WHILE,ENDWHILE,
    DO, ENDDO, FOR, TO, DOWNTO,
    /* multicharacter tokens */
    ID,NUM,
    /* special symbols */
    ASSIGN,EQ,LT,LTEQ,LTRT,PLUS,MINUS,TIMES,OVER,POWER,REM,
    LPAREN,RPAREN,SEMI
    };
    
    enum StateType{ START,INASSIGN,INPLUS,INLT,INCOMMENT,INNUM,INID,DONE };
    
    enum NodeKind{StmtK,ExpK};
    
    enum StmtKind{IfK,RepeatK,AssignK,ReadK,WriteK,WhileK,DowhileK,ForK};
    
    enum ExpKind{OpK,ConstK,IdK};
    
    enum ExpType{Void,Integer,Boolean};
       
    class TreeNode{
    public:
        TreeNode * child[3];
        TreeNode * sibling;
        NodeKind nodekind;
        union {StmtKind stmtkind; ExpKind expkind;} kind;
        union {
            TokenType op;
            int val;
            char * name;
        }attr;
        char * forType;
        ExpType type;
    };
    
    struct Token{
        TokenType type;
        string str;
        Token(TokenType t=END, string s=""){
            type = t;
            str = s;
        }
        Token(const Token &token){
            type = token.type;
            str = token.str;
        }
    };
    
    struct{ 
        string tokenString;
        TokenType tokenType;
    }reservedWords[MAXRESERVED]
    = {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
        {"repeat",REPEAT},{"until",UNTIL},{"read",READ},
        {"write",WRITE},{"while", WHILE},{"endwhile", ENDWHILE},
        {"do", DO}, {"for", FOR}, {"to", TO}, {"downto", DOWNTO},
        {"enddo", ENDDO}};
    
    class Core{
    public:
        string fileString = "";  //
        int strIndex = 0;
        Token token = Token();
    
    public:
        string run(const string &fs);
    
    public:
        TreeNode * parse(); //生成语法树
        string treeStr(TreeNode * root, int num); //获取语法数的字符串形式
        Token getToken();   //获取token
        char getNextChar();  //获取字符 
        void delTree(TreeNode * root);//删除语法树(防止系统开辟的动态内存过多)
    
        TreeNode * stmt_sequence();
        TreeNode * statement();
        TreeNode * if_stmt();
        TreeNode * repeat_stmt();
        TreeNode * assign_stmt();
        TreeNode * read_stmt();
        TreeNode * write_stmt();
        TreeNode * while_stmt();
        TreeNode * dowhile_stmt();
        TreeNode * for_stmt();
        TreeNode * exp();
        TreeNode * simple_exp();
        TreeNode * term();
        TreeNode * factor();
        TreeNode * powernum();
        void match(TokenType expected);
        TreeNode * newStmtNode(StmtKind kind);
        TreeNode * newExpNode(ExpKind kind);
        TokenType reservedLookup(string TokenString);
        static string tokenTypeStr(TokenType token);
    };
    
    string Core::run(const string &fs){
        strIndex = 0;
        fileString = fs;
        TreeNode * root = parse();
        string result = treeStr(root, 0);
        delTree(root);
        return result;
    }
    
    TreeNode * Core::parse(){
        TreeNode * t;
        token = getToken();
        t = stmt_sequence();
        if (token.type != ENDFILE)
            cout << "Code ends before file" << endl;
        return t;
    }
    
    string Core::treeStr(TreeNode * root, int num){
        string all = "";
        while(root != nullptr){
            string a = "";
            for(int i=0; i<num; ++i)
                a += " ";
            if(root->nodekind==StmtK){
                switch(root->kind.stmtkind){
                    case IfK:
                        a += "IF
    ";
                        break;
                    case RepeatK:
                        a += "Repeat
    ";
                        break;
                    case AssignK:
                        a += "Assign to ";
                        a += root->attr.name;
                        a += '
    ';
                        break;
                    case ReadK:
                        a += "Read ";
                        a += root->attr.name;
                        a += '
    ';
                        break;
                    case WriteK:
                        a += "Write
    ";
                        break;
                    case WhileK:
                        a += "While
    ";
                        break;
                    case DowhileK:
                        a += "Dowhile
    ";
                        break;
                    case ForK:
                        a += "For ";
                        a += root->attr.name;
                        a += root->forType;
                        a += '
    ';
                        break;
                    default:
                        break;
                }
            }
            else{
                switch(root->kind.expkind){
                    case OpK:
                        a += "Op: ";
                        a += tokenTypeStr(root->attr.op);
                        a += '
    ';
                        break;
                    case ConstK:
                        a += "Const: ";
                        a += to_string(root->attr.val);
                        a += '
    ';
                        break;
                    case IdK:
                        a += "Id: ";
                        a += root->attr.name;
                        a += '
    ';
                        break;
                    default:
                        break;
                }
            }
            for(int i=0; i<3; ++i){
                a += treeStr(root->child[i], num+2);
            }
            root = root->sibling;
            all += a;
        }
        return all;
    }
    
    void Core::delTree(TreeNode * root){
        if(root == nullptr)
            return;
        delTree(root->sibling);
        for(int i=0; i<3; ++i)
            delTree(root->child[i]);
        delete root;
    }
    
    char Core::getNextChar(){
        return fileString[strIndex++];
    }
    
    Token Core::getToken(){
        TokenType tokenType;
        string tokenString = "";
        StateType state = START;
        int save;
        while (state != DONE){ 
            char c = getNextChar();
            save = TRUE;
            switch (state)
            { 
                case START:
                if (isdigit(c))
                state = INNUM;
                else if (isalpha(c))
                state = INID;
                else if (c == ':')
                state = INASSIGN;
                else if (c == '+')
                state = INPLUS;
                else if (c == '<')
                state = INLT;
                else if ((c == ' ') || (c == '	') || (c == '
    '))
                save = FALSE;
                else if (c == '{')
                { save = FALSE;
                state = INCOMMENT;
                }
                else{   
                    state = DONE;
                    switch (c){ 
                        case '':
                        save = FALSE;
                        tokenType = ENDFILE;
                        break;
                        case '=':
                        tokenType = EQ;
                        break;
                        case '-':
                        tokenType = MINUS;
                        break;
                        case '*':
                        tokenType = TIMES;
                        break;
                        case '/':
                        tokenType = OVER;
                        break;
                        case '^':
                        tokenType = POWER;
                        break;
                        case '%':
                        tokenType = REM;
                        break;
                        case '(':
                        tokenType = LPAREN;
                        break;
                        case ')':
                        tokenType = RPAREN;
                        break;
                        case ';':
                        tokenType = SEMI;
                        break;
                        default:
                        tokenType = ERROR;
                        break;
                    }
                }
                break;
            case INCOMMENT:
                save = FALSE;
                if (c == '')
                { state = DONE;
                tokenType = ENDFILE;
                }
                else if (c == '}') state = START;
                break;
            case INASSIGN:
                state = DONE;
                if (c == '=')
                tokenType = ASSIGN;
                else{
                --strIndex;
                save = FALSE;
                tokenType = ERROR;
                }
                break;
            case INPLUS:
                state = DONE;
                if(c == '=')
                tokenType = ASSIGN;
                else{
                    --strIndex;
                    save = FALSE;
                    tokenType = PLUS;
                }
                break;
            case INLT:
                state = DONE;
                if(c == '=')
                tokenType = LTEQ;
                else if(c == '>')
                tokenType = LTRT;
                else{
                    --strIndex;
                    save = FALSE;
                    tokenType = LT;
                }
                break;
            case INNUM:
                if (!isdigit(c))
                { /* backup in the input */
                --strIndex;
                save = FALSE;
                state = DONE;
                tokenType = NUM;
                }
                break;
            case INID:
                if (!isalpha(c))
                { /* backup in the input */
                --strIndex;
                save = FALSE;
                state = DONE;
                tokenType = ID;
                }
                break;
            case DONE:
            default: /* should never happen */
                state = DONE;
                tokenType = ERROR;
                break;
            }
            if (save)
                tokenString += c;
            if (state == DONE)
            { 
                if (tokenType == ID)
                    tokenType = reservedLookup(tokenString);
            }
        }
        return Token(tokenType, tokenString);
    }
    
    TokenType Core::reservedLookup(string tokenString){
        for(int i=0; i<MAXRESERVED; ++i){
            if (tokenString == reservedWords[i].tokenString)
                return reservedWords[i].tokenType;
        }
        return ID;
    }
    
    TreeNode * Core::stmt_sequence(){
        TreeNode * t = statement();
        TreeNode * p = t;
        TreeNode * q;
        match(SEMI);
        while((token.type==IF) || (token.type==REPEAT) || 
        (token.type==ID) || (token.type==READ) || (token.type==WRITE) ||
        (token.type==WHILE) || (token.type==DO) || (token.type==FOR)){
            q = statement();
            if(q!=nullptr){
                if(t==nullptr) t = p = q;
                else{
                    p->sibling = q;
                    p = q;
                }
            }
            match(SEMI);
        }
        return t; 
    }
    
    TreeNode * Core::statement()
    { TreeNode * t = nullptr;
      switch (token.type) {
        case IF : t = if_stmt(); break;
        case REPEAT : t = repeat_stmt(); break;
        case ID : t = assign_stmt(); break;
        case READ : t = read_stmt(); break;
        case WRITE : t = write_stmt(); break;
        case WHILE : t = while_stmt(); break;
        case DO: t = dowhile_stmt(); break;
        case FOR: t = for_stmt(); break;
        default: 
                token = getToken();
                break;
      } 
      return t;
    }
    
    TreeNode * Core::if_stmt(void)
    { TreeNode * t = newStmtNode(IfK);
      match(IF);
      match(LPAREN);
      if (t!=nullptr) t->child[0] = exp();
      match(RPAREN);
      if (t!=nullptr) t->child[1] = stmt_sequence();
      if (token.type==ELSE) {
        match(ELSE);
        if (t!=nullptr) t->child[2] = stmt_sequence();
      }
      return t;
    }
    
    TreeNode * Core::repeat_stmt(void)
    { TreeNode * t = newStmtNode(RepeatK);
      match(REPEAT);
      if (t!=nullptr) t->child[0] = stmt_sequence();
      match(UNTIL);
      if (t!=nullptr) t->child[1] = exp();
      return t;
    }
    
    TreeNode * Core::assign_stmt(void)
    { TreeNode * t = newStmtNode(AssignK);
      if ((t!=nullptr) && (token.type==ID)){
        t->attr.name = new char[token.str.size()+1];
        strcpy(t->attr.name, token.str.c_str());
      }
      match(ID);
      match(ASSIGN);
      if (t!=nullptr) t->child[0] = exp();
      return t;
    }
    
    TreeNode * Core::read_stmt(void)
    { TreeNode * t = newStmtNode(ReadK);
      match(READ);
      if ((t!=nullptr) && (token.type==ID)){
        t->attr.name = new char[token.str.size()+1];
        strcpy(t->attr.name, token.str.c_str());
      }
      match(ID);
      return t;
    }
    
    TreeNode * Core::write_stmt(void)
    { TreeNode * t = newStmtNode(WriteK);
      match(WRITE);
      if (t!=nullptr) t->child[0] = exp();
      return t;
    }
    
    TreeNode * Core::while_stmt(void){
        TreeNode * t = newStmtNode(WhileK);
        match(WHILE);
        match(LPAREN);
        if(t!=nullptr) t->child[0] = exp();
        match(RPAREN);
        if(t!=nullptr) t->child[1] = stmt_sequence();
        match(ENDWHILE);
        return t;
    }
    
    TreeNode * Core::dowhile_stmt(void){
        TreeNode * t = newStmtNode(DowhileK);
        match(DO);
        if(t!=nullptr) t->child[0] = stmt_sequence();
        match(WHILE);
        match(LPAREN);
        if(t!=nullptr) t->child[1] = exp();
        match(RPAREN);
        return t;
    }
    
    TreeNode * Core::for_stmt(void){
        TreeNode * t = newStmtNode(ForK);
        if ((t!=nullptr) && (token.type==ID)){
            t->attr.name = new char[token.str.size()+1];
            strcpy(t->attr.name, token.str.c_str());
        }
        match(ID);
        match(ASSIGN);
        if (t!=nullptr) t->child[0] = simple_exp();
        if(token.type == TO){
            t->forType = "To";
            match(TO);
        }
        else{
            t->forType = "Downto";
            match(DOWNTO);
        }
        if (t!=nullptr) t->child[1] = simple_exp();
        match(DO);
        if (t!=nullptr) t->child[2] = stmt_sequence();
        match(ENDDO);
        return t;
    }
    
    TreeNode * Core::exp(void)
    { TreeNode * t = simple_exp();
      if ((token.type==LT)||(token.type==EQ)||(token.type==LTEQ)||(token.type==LTRT)) {
        TreeNode * p = newExpNode(OpK);
        if (p!=nullptr) {
          p->child[0] = t;
          p->attr.op = token.type;
          t = p;
        }
        match(token.type);
        if (t!=nullptr)
          t->child[1] = simple_exp();
      }
      return t;
    }
    
    TreeNode * Core::simple_exp(void)
    { TreeNode * t = term();
      while ((token.type==PLUS)||(token.type==MINUS)||(token.type==REM))
      { TreeNode * p = newExpNode(OpK);
        if (p!=nullptr) {
          p->child[0] = t;
          p->attr.op = token.type;
          t = p;
          match(token.type);
          t->child[1] = term();
        }
      }
      return t;
    }
    
    TreeNode * Core::term(void)
    { TreeNode * t = factor();
      while ((token.type==TIMES)||(token.type==OVER))
      { TreeNode * p = newExpNode(OpK);
        if (p!=nullptr) {
          p->child[0] = t;
          p->attr.op = token.type;
          t = p;
          match(token.type);
          p->child[1] = factor();
        }
      }
      return t;
    }
    
    TreeNode * Core::factor(void){
        TreeNode * t = powernum();
        while(token.type==POWER){
            TreeNode * p = newExpNode(OpK);
            if(p!=nullptr){
                p->child[0] = t;
                p->attr.op = token.type;
                t = p;
                match(token.type);
                p->child[1] = powernum();
            }
        }
        return t;
    }
    
    TreeNode * Core::powernum(void)
    { TreeNode * t = nullptr;
      switch (token.type) {
        case NUM :
          t = newExpNode(ConstK);
          if ((t!=nullptr) && (token.type==NUM))
            t->attr.val = stoi(token.str);
          match(NUM);
          break;
        case ID :
          t = newExpNode(IdK);
          if ((t!=nullptr) && (token.type==ID)){
            t->attr.name = new char[token.str.size()+1];
            strcpy(t->attr.name, token.str.c_str());
          }
          match(ID);
          break;
        case LPAREN :
          match(LPAREN);
          t = exp();
          match(RPAREN);
          break;
        default:
          token = getToken();
          break;
        }
      return t;
    }
    
    void Core::match(TokenType expected)
    { 
        if (token.type == expected) token = getToken();
    }
    
    TreeNode * Core::newStmtNode(StmtKind kind)
    { 
      TreeNode * t = new TreeNode();
      int i;
      if (t==nullptr)
        cout << "Out of memory error at line
    ";
      else {
        for (i=0;i<3;i++) t->child[i] = nullptr;
        t->sibling = nullptr;
        t->nodekind = StmtK;
        t->kind.stmtkind = kind;
      }
      return t;
    }
    
    TreeNode * Core::newExpNode(ExpKind kind)
    {
      TreeNode * t = new TreeNode();
      int i;
      if (t==nullptr)
        cout << "Out of memory error at line
    ";
      else {
        for (i=0;i<3;i++) t->child[i] = nullptr;
        t->sibling = nullptr;
        t->nodekind = ExpK;
        t->kind.expkind = kind;
        t->type = Void;
      }
      return t;
    }
    
    string Core::tokenTypeStr(TokenType token){
        switch(token){
            case 0:
                return "ENDFILE";
            case 1:
                return "ERROR";
            case 2:
                return "IF";
            case 3:
                return "THEN";
            case 4:
                return "ELSE";
            case 5:
                return "END";
            case 6:
                return "REPEAT";
            case 7:
                return "UNTIL";
            case 8:
                return "READ";
            case 9:
                return "WRITE";
            case 10:
                return "WHILE";
            case 11:
                return "ENDWHILE";
            case 12:
                return "DO";
            case 13:
                return "ENDDO";
            case 14:
                return "FOR";
            case 15:
                return "TO";
            case 16:
                return "DOWNTO"; 
            case 17:
                return "ID";
            case 18:
                return "NUM";
            case 19:
                return "ASSIGN";
            case 20:
                return "EQ";
            case 21:
                return "LT";
            case 22:
                return "LTEQ";
            case 23:
                return "LTRT";
            case 24:
                return "PLUS";
            case 25:
                return "MINUS";
            case 26:
                return "TIMES";
            case 27:
                return "OVER";
            case 28:
                return "POWER";
            case 29:
                return "REM";
            case 30:
                return "LPAREN";
            case 31:
                return "RPAREN";
            case 32:
                return "SEMI";
        }
    }
    
    int main(){
        ifstream in("source.tny", ios::in);
        istreambuf_iterator<char> beg(in), end;
        string str(beg, end);
        in.close(); 
        Core core;
        string result = core.run(str);
        cout << result;
    }
    

    可视化界面(QT)

    代码
    global.h

    #ifndef _GLOBAL_H_
    #define _GLOBAL_H_
    
    #include <string>
    using namespace std;
    #define MAXRESERVED 15
    #define TRUE 1
    #define FALSE 0
    
    enum TokenType
    /* book-keeping tokens */
    {ENDFILE,ERROR,
    /* reserved words */
    IF,THEN,ELSE,END,REPEAT,UNTIL,READ,WRITE,WHILE,ENDWHILE,
    DO, ENDDO, FOR, TO, DOWNTO,
    /* multicharacter tokens */
    ID,NUM,
    /* special symbols */
    ASSIGN,EQ,LT,LTEQ,LTRT,PLUS,MINUS,TIMES,OVER,POWER,REM,
    LPAREN,RPAREN,SEMI
    };
    
    enum StateType{ START,INASSIGN,INPLUS,INLT,INCOMMENT,INNUM,INID,DONE };
    
    enum NodeKind{StmtK,ExpK};
    
    enum StmtKind{IfK,RepeatK,AssignK,ReadK,WriteK,WhileK,DowhileK,ForK};
    
    enum ExpKind{OpK,ConstK,IdK};
    
    enum ExpType{Void,Integer,Boolean};
       
    class TreeNode{
    public:
        TreeNode * child[3];
        TreeNode * sibling;
        NodeKind nodekind;
        union {StmtKind stmtkind; ExpKind expkind;} kind;
        union {
            TokenType op;
            int val;
            char * name;
        }attr;
        char * forType;
        ExpType type;
    };
    
    struct Token{
        TokenType type;
        string str;
        Token(TokenType t=END, string s=""){
            type = t;
            str = s;
        }
        Token(const Token &token){
            type = token.type;
            str = token.str;
        }
    };
    
    struct{ 
        string tokenString;
        TokenType tokenType;
    }reservedWords[MAXRESERVED]
    = {{"if",IF},{"then",THEN},{"else",ELSE},{"end",END},
        {"repeat",REPEAT},{"until",UNTIL},{"read",READ},
        {"write",WRITE},{"while", WHILE},{"endwhile", ENDWHILE},
        {"do", DO}, {"for", FOR}, {"to", TO}, {"downto", DOWNTO},
        {"enddo", ENDDO}};
    
    #endif
    

    core.h

    #ifndef _CORE_H_
    #define _CORE_H_
    
    #include <string>
    #include "global.h"
    using namespace std;
    
    class Core{
    public:
        string fileString = "";  //
        int strIndex = 0;
        Token token = Token();
    
    public:
        string run(const string &fs);
    
    public:
        TreeNode * parse(); //生成语法树
        string treeStr(TreeNode * root, int num); //获取语法数的字符串形式
        Token getToken();   //获取token
        char getNextChar();  //获取字符 
        void delTree(TreeNode * root);//删除语法树(防止系统开辟的动态内存过多)
    
        TreeNode * stmt_sequence();
        TreeNode * statement();
        TreeNode * if_stmt();
        TreeNode * repeat_stmt();
        TreeNode * assign_stmt();
        TreeNode * read_stmt();
        TreeNode * write_stmt();
        TreeNode * while_stmt();
        TreeNode * dowhile_stmt();
        TreeNode * for_stmt();
        TreeNode * exp();
        TreeNode * simple_exp();
        TreeNode * term();
        TreeNode * factor();
        TreeNode * powernum();
        void match(TokenType expected);
        TreeNode * newStmtNode(StmtKind kind);
        TreeNode * newExpNode(ExpKind kind);
        TokenType reservedLookup(string TokenString);
        static string tokenTypeStr(TokenType token);
    };
    
    #endif
    

    core.cpp

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <string.h>
    #include "core.h"
    using namespace std;
    
    /*********************************************************
    创建核心类Core,功能为:
    (1) 类中拥有属性fileString,并且该fileString内容
    可以被更改
    (2) char getNextChar(); 读取fileString中的字符
    (3) Token getToken(); 返回Token对象(tokenType, tokenString)
    (4) TreeNode * parse(); 返回一棵语法树
    (5) string treeStr(); 将语法树以字符串的形式呈现
    *********************************************************/
    
    
    string Core::run(const string &fs){
        strIndex = 0;
        fileString = fs;
        TreeNode * root = parse();
        string result = treeStr(root, 0);
        delTree(root);
        return result;
    }
    
    TreeNode * Core::parse(){
        TreeNode * t;
        token = getToken();
        t = stmt_sequence();
        if (token.type != ENDFILE)
            cout << "Code ends before file" << endl;
        return t;
    }
    
    string Core::treeStr(TreeNode * root, int num){
        string all = "";
        while(root != nullptr){
            string a = "";
            for(int i=0; i<num; ++i)
                a += " ";
            if(root->nodekind==StmtK){
                switch(root->kind.stmtkind){
                    case IfK:
                        a += "IF
    ";
                        break;
                    case RepeatK:
                        a += "Repeat
    ";
                        break;
                    case AssignK:
                        a += "Assign to ";
                        a += root->attr.name;
                        a += '
    ';
                        break;
                    case ReadK:
                        a += "Read ";
                        a += root->attr.name;
                        a += '
    ';
                        break;
                    case WriteK:
                        a += "Write
    ";
                        break;
                    case WhileK:
                        a += "While
    ";
                        break;
                    case DowhileK:
                        a += "Dowhile
    ";
                        break;
                    case ForK:
                        a += "For ";
                        a += root->attr.name;
                        a += " ";
                        a += root->forType;
                        a += '
    ';
                        break;
                    default:
                        break;
                }
            }
            else{
                switch(root->kind.expkind){
                    case OpK:
                        a += "Op: ";
                        a += tokenTypeStr(root->attr.op);
                        a += '
    ';
                        break;
                    case ConstK:
                        a += "Const: ";
                        a += to_string(root->attr.val);
                        a += '
    ';
                        break;
                    case IdK:
                        a += "Id: ";
                        a += root->attr.name;
                        a += '
    ';
                        break;
                    default:
                        break;
                }
            }
            for(int i=0; i<3; ++i){
                a += treeStr(root->child[i], num+2);
            }
            root = root->sibling;
            all += a;
        }
        return all;
    }
    
    void Core::delTree(TreeNode * root){
        if(root == nullptr)
            return;
        delTree(root->sibling);
        for(int i=0; i<3; ++i)
            delTree(root->child[i]);
        delete root;
    }
    
    char Core::getNextChar(){
        return fileString[strIndex++];
    }
    
    Token Core::getToken(){
        TokenType tokenType;
        string tokenString = "";
        StateType state = START;
        int save;
        while (state != DONE){ 
            char c = getNextChar();
            save = TRUE;
            switch (state)
            { 
                case START:
                if (isdigit(c))
                state = INNUM;
                else if (isalpha(c))
                state = INID;
                else if (c == ':')
                state = INASSIGN;
                else if (c == '+')
                state = INPLUS;
                else if (c == '<')
                state = INLT;
                else if ((c == ' ') || (c == '	') || (c == '
    '))
                save = FALSE;
                else if (c == '{')
                { save = FALSE;
                state = INCOMMENT;
                }
                else{   
                    state = DONE;
                    switch (c){ 
                        case '':
                        save = FALSE;
                        tokenType = ENDFILE;
                        break;
                        case '=':
                        tokenType = EQ;
                        break;
                        case '-':
                        tokenType = MINUS;
                        break;
                        case '*':
                        tokenType = TIMES;
                        break;
                        case '/':
                        tokenType = OVER;
                        break;
                        case '^':
                        tokenType = POWER;
                        break;
                        case '%':
                        tokenType = REM;
                        break;
                        case '(':
                        tokenType = LPAREN;
                        break;
                        case ')':
                        tokenType = RPAREN;
                        break;
                        case ';':
                        tokenType = SEMI;
                        break;
                        default:
                        tokenType = ERROR;
                        break;
                    }
                }
                break;
            case INCOMMENT:
                save = FALSE;
                if (c == '')
                { state = DONE;
                tokenType = ENDFILE;
                }
                else if (c == '}') state = START;
                break;
            case INASSIGN:
                state = DONE;
                if (c == '=')
                tokenType = ASSIGN;
                else{
                --strIndex;
                save = FALSE;
                tokenType = ERROR;
                }
                break;
            case INPLUS:
                state = DONE;
                if(c == '=')
                tokenType = ASSIGN;
                else{
                    --strIndex;
                    save = FALSE;
                    tokenType = PLUS;
                }
                break;
            case INLT:
                state = DONE;
                if(c == '=')
                tokenType = LTEQ;
                else if(c == '>')
                tokenType = LTRT;
                else{
                    --strIndex;
                    save = FALSE;
                    tokenType = LT;
                }
                break;
            case INNUM:
                if (!isdigit(c))
                { /* backup in the input */
                --strIndex;
                save = FALSE;
                state = DONE;
                tokenType = NUM;
                }
                break;
            case INID:
                if (!isalpha(c))
                { /* backup in the input */
                --strIndex;
                save = FALSE;
                state = DONE;
                tokenType = ID;
                }
                break;
            case DONE:
            default: /* should never happen */
                state = DONE;
                tokenType = ERROR;
                break;
            }
            if (save)
                tokenString += c;
            if (state == DONE)
            { 
                if (tokenType == ID)
                    tokenType = reservedLookup(tokenString);
            }
        }
        return Token(tokenType, tokenString);
    }
    
    TokenType Core::reservedLookup(string tokenString){
        for(int i=0; i<MAXRESERVED; ++i){
            if (tokenString == reservedWords[i].tokenString)
                return reservedWords[i].tokenType;
        }
        return ID;
    }
    
    TreeNode * Core::stmt_sequence(){
        TreeNode * t = statement();
        TreeNode * p = t;
        TreeNode * q;
        match(SEMI);
        while((token.type==IF) || (token.type==REPEAT) || 
        (token.type==ID) || (token.type==READ) || (token.type==WRITE) ||
        (token.type==WHILE) || (token.type==DO) || (token.type==FOR)){
            q = statement();
            if(q!=nullptr){
                if(t==nullptr) t = p = q;
                else{
                    p->sibling = q;
                    p = q;
                }
            }
            match(SEMI);
        }
        return t; 
    }
    
    TreeNode * Core::statement()
    { TreeNode * t = nullptr;
      switch (token.type) {
        case IF : t = if_stmt(); break;
        case REPEAT : t = repeat_stmt(); break;
        case ID : t = assign_stmt(); break;
        case READ : t = read_stmt(); break;
        case WRITE : t = write_stmt(); break;
        case WHILE : t = while_stmt(); break;
        case DO: t = dowhile_stmt(); break;
        case FOR: t = for_stmt(); break;
        default: 
                token = getToken();
                break;
      } 
      return t;
    }
    
    TreeNode * Core::if_stmt(void)
    { TreeNode * t = newStmtNode(IfK);
      match(IF);
      match(LPAREN);
      if (t!=nullptr) t->child[0] = exp();
      match(RPAREN);
      if (t!=nullptr) t->child[1] = stmt_sequence();
      if (token.type==ELSE) {
        match(ELSE);
        if (t!=nullptr) t->child[2] = stmt_sequence();
      }
      return t;
    }
    
    TreeNode * Core::repeat_stmt(void)
    { TreeNode * t = newStmtNode(RepeatK);
      match(REPEAT);
      if (t!=nullptr) t->child[0] = stmt_sequence();
      match(UNTIL);
      if (t!=nullptr) t->child[1] = exp();
      return t;
    }
    
    TreeNode * Core::assign_stmt(void)
    { TreeNode * t = newStmtNode(AssignK);
      if ((t!=nullptr) && (token.type==ID)){
        t->attr.name = new char[token.str.size()+1];
        strcpy(t->attr.name, token.str.c_str());
      }
      match(ID);
      match(ASSIGN);
      if (t!=nullptr) t->child[0] = exp();
      return t;
    }
    
    TreeNode * Core::read_stmt(void)
    { TreeNode * t = newStmtNode(ReadK);
      match(READ);
      if ((t!=nullptr) && (token.type==ID)){
        t->attr.name = new char[token.str.size()+1];
        strcpy(t->attr.name, token.str.c_str());
      }
      match(ID);
      return t;
    }
    
    TreeNode * Core::write_stmt(void)
    { TreeNode * t = newStmtNode(WriteK);
      match(WRITE);
      if (t!=nullptr) t->child[0] = exp();
      return t;
    }
    
    TreeNode * Core::while_stmt(void){
        TreeNode * t = newStmtNode(WhileK);
        match(WHILE);
        match(LPAREN);
        if(t!=nullptr) t->child[0] = exp();
        match(RPAREN);
        if(t!=nullptr) t->child[1] = stmt_sequence();
        match(ENDWHILE);
        return t;
    }
    
    TreeNode * Core::dowhile_stmt(void){
        TreeNode * t = newStmtNode(DowhileK);
        match(DO);
        if(t!=nullptr) t->child[0] = stmt_sequence();
        match(WHILE);
        match(LPAREN);
        if(t!=nullptr) t->child[1] = exp();
        match(RPAREN);
        return t;
    }
    
    TreeNode * Core::for_stmt(void){
        TreeNode * t = newStmtNode(ForK);
        match(FOR);
        if ((t!=nullptr) && (token.type==ID)){
            t->attr.name = new char[token.str.size()+1];
            strcpy(t->attr.name, token.str.c_str());
        }
        match(ID);
        match(ASSIGN);
        if (t!=nullptr) t->child[0] = simple_exp();
        if(token.type == TO){
            t->forType = "To";
            match(TO);
        }
        else{
            t->forType = "Downto";
            match(DOWNTO);
        }
        if (t!=nullptr) t->child[1] = simple_exp();
        match(DO);
        if (t!=nullptr) t->child[2] = stmt_sequence();
        match(ENDDO);
        return t;
    }
    
    TreeNode * Core::exp(void)
    { TreeNode * t = simple_exp();
      if ((token.type==LT)||(token.type==EQ)||(token.type==LTEQ)||(token.type==LTRT)) {
        TreeNode * p = newExpNode(OpK);
        if (p!=nullptr) {
          p->child[0] = t;
          p->attr.op = token.type;
          t = p;
        }
        match(token.type);
        if (t!=nullptr)
          t->child[1] = simple_exp();
      }
      return t;
    }
    
    TreeNode * Core::simple_exp(void)
    { TreeNode * t = term();
      while ((token.type==PLUS)||(token.type==MINUS)||(token.type==REM))
      { TreeNode * p = newExpNode(OpK);
        if (p!=nullptr) {
          p->child[0] = t;
          p->attr.op = token.type;
          t = p;
          match(token.type);
          t->child[1] = term();
        }
      }
      return t;
    }
    
    TreeNode * Core::term(void)
    { TreeNode * t = factor();
      while ((token.type==TIMES)||(token.type==OVER))
      { TreeNode * p = newExpNode(OpK);
        if (p!=nullptr) {
          p->child[0] = t;
          p->attr.op = token.type;
          t = p;
          match(token.type);
          p->child[1] = factor();
        }
      }
      return t;
    }
    
    TreeNode * Core::factor(void){
        TreeNode * t = powernum();
        while(token.type==POWER){
            TreeNode * p = newExpNode(OpK);
            if(p!=nullptr){
                p->child[0] = t;
                p->attr.op = token.type;
                t = p;
                match(token.type);
                p->child[1] = powernum();
            }
        }
        return t;
    }
    
    TreeNode * Core::powernum(void)
    { TreeNode * t = nullptr;
      switch (token.type) {
        case NUM :
          t = newExpNode(ConstK);
          if ((t!=nullptr) && (token.type==NUM))
            t->attr.val = stoi(token.str);
          match(NUM);
          break;
        case ID :
          t = newExpNode(IdK);
          if ((t!=nullptr) && (token.type==ID)){
            t->attr.name = new char[token.str.size()+1];
            strcpy(t->attr.name, token.str.c_str());
          }
          match(ID);
          break;
        case LPAREN :
          match(LPAREN);
          t = exp();
          match(RPAREN);
          break;
        default:
          token = getToken();
          break;
        }
      return t;
    }
    
    void Core::match(TokenType expected)
    { 
        if (token.type == expected) token = getToken();
    }
    
    TreeNode * Core::newStmtNode(StmtKind kind)
    { 
      TreeNode * t = new TreeNode();
      int i;
      if (t==nullptr)
        cout << "Out of memory error at line
    ";
      else {
        for (i=0;i<3;i++) t->child[i] = nullptr;
        t->sibling = nullptr;
        t->nodekind = StmtK;
        t->kind.stmtkind = kind;
      }
      return t;
    }
    
    TreeNode * Core::newExpNode(ExpKind kind)
    {
      TreeNode * t = new TreeNode();
      int i;
      if (t==nullptr)
        cout << "Out of memory error at line
    ";
      else {
        for (i=0;i<3;i++) t->child[i] = nullptr;
        t->sibling = nullptr;
        t->nodekind = ExpK;
        t->kind.expkind = kind;
        t->type = Void;
      }
      return t;
    }
    
    string Core::tokenTypeStr(TokenType token){
        switch(token){
            case 0:
                return "ENDFILE";
            case 1:
                return "ERROR";
            case 2:
                return "IF";
            case 3:
                return "THEN";
            case 4:
                return "ELSE";
            case 5:
                return "END";
            case 6:
                return "REPEAT";
            case 7:
                return "UNTIL";
            case 8:
                return "READ";
            case 9:
                return "WRITE";
            case 10:
                return "WHILE";
            case 11:
                return "ENDWHILE";
            case 12:
                return "DO";
            case 13:
                return "ENDDO";
            case 14:
                return "FOR";
            case 15:
                return "TO";
            case 16:
                return "DOWNTO"; 
            case 17:
                return "ID";
            case 18:
                return "NUM";
            case 19:
                return "ASSIGN";
            case 20:
                return "EQ";
            case 21:
                return "LT";
            case 22:
                return "LTEQ";
            case 23:
                return "LTRT";
            case 24:
                return "PLUS";
            case 25:
                return "MINUS";
            case 26:
                return "TIMES";
            case 27:
                return "OVER";
            case 28:
                return "POWER";
            case 29:
                return "REM";
            case 30:
                return "LPAREN";
            case 31:
                return "RPAREN";
            case 32:
                return "SEMI";
        }
    }
    

    mywindow.h

    #ifndef _MYWINDOW_H_
    #define _MYWINDOW_H_
    
    #include <QMainWindow>
    #include <QPlainTextEdit>
    #include "core.h"
    
    class Mywindow : public QMainWindow{
        Q_OBJECT
    
    private:
        QPlainTextEdit * edit1, * edit2;
        QAction * openAction;
        QAction * saveAction;
        QAction * runAction;
        Core * core;
    
    public:
        explicit Mywindow(QWidget *parent = nullptr);
    
    signals: //用来声明信号函数
    
    public slots: //用来声明槽函数
        void open();
        void save();
        void run();
    };
    
    #endif
    

    mywindow.cpp

    #include "mywindow.h"
    #include <QAction>
    #include <QMenuBar>
    #include <QToolBar>
    #include <QHBoxLayout>
    #include <iostream>
    #include <QFileDialog>
    #include <fstream>
    using namespace std;
    
    Mywindow::Mywindow(QWidget * parent) : QMainWindow(parent){
        setWindowTitle(tr("Main Window"));
        //文本编辑框
        edit1 = new QPlainTextEdit(this);
        edit2 = new QPlainTextEdit(this);
        QWidget * cw = new QWidget();
        QHBoxLayout * layout = new QHBoxLayout(cw);
        layout->addWidget(edit1);
        layout->addWidget(edit2);
        setCentralWidget(cw);
        //动作
        openAction = new QAction(QIcon(":/images/open"), tr("&Open..."), this);
        openAction->setStatusTip(tr("Open a source file"));
        runAction = new QAction(QIcon(":/images/run"), tr("&Run..."), this);
        runAction->setStatusTip(tr("Run the program"));
        saveAction = new QAction(QIcon(":/images/save"), tr("&Save..."), this);
        saveAction->setStatusTip(tr("Save the source file"));
        connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
        connect(runAction, SIGNAL(triggered()), this, SLOT(run()));
        connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
        //工具栏
        QToolBar * openToolBar = addToolBar(tr("&Open"));
        openToolBar->addAction(openAction);
        QToolBar * saveToolBar = addToolBar(tr("&Save"));
        saveToolBar->addAction(saveAction);
        QToolBar * runToolBar = addToolBar(tr("&Run"));
        runToolBar->addAction(runAction);
        
        //状态栏
        statusBar();
        //core
        core = new Core();
    }
    
    void Mywindow::open(){
        QString openfilename = QFileDialog::getOpenFileName(this,
        tr("Open File"), "", "", 0);
        if(!openfilename.isNull()){
            string filename = openfilename.toStdString();
            ifstream in(filename, ios::in);
            istreambuf_iterator<char> beg(in), end;
            string str(beg, end);
            in.close();
            edit1->setPlainText(QString::fromStdString(str));   
        }
    }
    
    void Mywindow::save(){
        QString savefilename = QFileDialog::getSaveFileName(this,
        tr("Open Config"), "", "Config Files (*.tny)");
        if(!savefilename.isNull()){
            string filename = savefilename.toStdString();
            fstream out(filename, ios::out);
            out << edit1->toPlainText().toStdString();
            out.close();
        }
    }
    
    void Mywindow::run(){
        QString s = edit1->toPlainText();
        QString result = QString::fromStdString(core->run(s.toStdString()));
        edit2->setPlainText(result);
    }
    

    main.cpp

    #include "mywindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[]){
        //应用程序抽象类
        QApplication app(argc, argv);
        //窗口
        Mywindow w;
        w.show();
        //进入消息循环,一直接受消息,直到窗口被关闭
        return app.exec();
    }
    

    res.qrc

    <RCC>
        <qresource prefix="/images">
            <file alias="open">open.jpg</file>
        </qresource>
        <qresource prefix="/images/">
            <file alias="run">run.jpg</file>
        </qresource>
        <qresource prefix="/images/">
            <file alias="save">save.jpg</file>
        </qresource>
    </RCC>
    

  • 相关阅读:
    新手silverlight练习五子棋( 二 )
    VS注释模板工具
    NET简介
    MS Sql server 总结(命令恢复)
    Highcharts入门(一)
    jqGrid入门(1)
    WIN7常见问题汇总
    log4net入门
    DLL管理工具
    C++回顾1 简介
  • 原文地址:https://www.cnblogs.com/Serenaxy/p/14022821.html
Copyright © 2011-2022 走看看