Operator precedence grammar - infix expression into postfix notation and evaluation

Operator precedence grammar - infix expression into postfix notation and evaluation

According compiler theory of knowledge, we can be the entire program is divided into three parts, lexical analysis, grammar analysis, postfix expression computing, in grammar analysis will involve operator precedence judgment. Next, I will explain the code sub-module, the reader may wish to understand operator precedence grammar, lexical analysis and have postfix expression help.

Code may identify four basic arithmetic exponentiation and comprising brackets, a float can be identified, the error handling operation is not performed when an error.

Operator Precedence

As shown in Array sp, 1 denotes the outer stack higher priority than the priority of the stack, the stack -1 represents the priority lower than the priority of the stack outside, 0 indicates equal priority, require special handling, 99 denotes an input error, the symbol is not or unrecognized input character matches.

For +, -, *, / four operators, since priority in the binding of the left operator, the same reference numerals stack higher than the priority of the external stack; and exponentiation with a right binding, therefore, two an outer ^ compared to stack higher priority than the priority of the stack.

For two different operators, the highest priority, exponentiation () is higher than multiplication and division, subtraction, multiplication and division above.

int SignPriority(char in, char out) {
    int sp[9][9] = {{ 1,  1, -1, -1, -1, -1,  1,  1, 99},  //'+'
                    { 1,  1, -1, -1, -1, -1,  1,  1, 99},  //'-'
                    { 1,  1,  1,  1, -1, -1,  1,  1, 99},  //'*'
                    { 1,  1,  1,  1, -1, -1,  1,  1, 99},  //'/'
                    { 1,  1,  1,  1, -1, -1,  1,  1, 99},  //'^'
                    {-1, -1, -1, -1, -1, -1,  0, 99, 99},  //'('
                    { 1,  1,  1,  1,  1, 99,  1,  1, 99},  //')'
                    {-1, -1, -1, -1, -1, -1, 99,  0, 99},  //'#'
                    {99, 99, 99, 99, 99, 99, 99, 99, 99}}; //other
                  //  +,  -,  *,  /,  ^,  (,  ),  #, other
    return sp[Sign2Num(in)][Sign2Num(out)];
}

Necessary data structures

struct Word denotes a lexical analysis of the recognized word, flag = true is represented by a digital word, flag = false word is expressed operator.

struct Word {
    bool flag;
    double num;
    char sign;
};

lexical analysis

Lexical analysis, the floating-point number can be identified, it can be used for negative zero by subtracting the number. The formula reads as a string, and at the end to add "#" as the end. Identifying a first character from the beginning, if the identification number, identification continues backwards until the operator identification, as a digital word pushed into the container, a fallback character. If it is identified to the operator, as a primary pressure directly into the container until the identification "#" so far.

vector<Word> LexicalAnalysis(string func) {
    func = func+ "#";
    int l = func.length();
    vector<Word> ans;
    for (int i = 0; i < l; i++) {
        if (func[i] >= '0' && func[i] <= '9') {
            double num = 0;
            bool df = false;
            double mi = 0;
            for ( ; i < l; i++) {
                if (!df) {
                    if (func[i] >= '0' && func[i] <= '9') {
                        num = num * 10 + static_cast<double>(func[i] - '0');
                    }
                    else if (func[i] == '.') {
                        df = true;
                        mi = 10.0;
                    }
                }
                else {
                    if (func[i] >= '0' && func[i] <= '9') {
                        num = num + (func[i] - '0') / mi;
                        mi *= 10;
                    }
                }
                if (!(func[i] >= '0' && func[i] <= '9') && (func[i] != '.')){
                    Word n;
                    n.flag = true;
                    n.num = num;
                    ans.push_back(n);
                    num = 0;
                    break;
                }
            }
            i--;
        }
        else {
            Word s;
            s.flag = false;
            s.sign = func[i];
            if (s.sign != '#') {
                ans.push_back(s);
            }
        }
    }
    return ans;
}

Parsing

In the syntax analysis, we used a container for storing the postfix expression, sequentially reads out the postfix expression container of operation is also desired. Reading a word from the lexical container, if the digital word, the container pushed into the postfix expression; If the word is the operator, the comparison operator pressed the stack, the stack operators, previously pressed into "# ", to facilitate comparison operator precedence.

Each read an operator, comparing the priority of the operator and the operator of the top of the stack, the stack is read operator Sinotrans operator, operator stack within a stack operator. If the operator stacks a higher priority than the priority of operator sinotrans stack, the top element from the stack, the stack is read into the operator; below the contrary, the operator is read directly into the stack. When reading the right parenthesis ")", all the operator stacks the stack until it encounters the left bracket "(."

After reading unit complete words, all operations Operators symbol stack the stack. All the stack postfix operators into the container.

vector<Word> ParseAnalysis(vector<Word> lpword) {
    stack<Word> SignStack;
    vector<Word> ans;
    Word fst;
    fst.flag = false;
    fst.sign = '#';
    SignStack.push(fst);
    for (Word w : lpword) {
        if (w.flag) {
            ans.push_back(w);
        }
        else {
            if (w.sign == ')') {
                while (!SignStack.empty()) {
                    if (SignStack.top().sign == '(') {
                        SignStack.pop();
                        break;
                    }
                    ans.push_back(SignStack.top());
                    SignStack.pop();
                }
            }
            else if (SignPriority(SignStack.top().sign, w.sign) > 0) {
                ans.push_back(SignStack.top());
                SignStack.pop();
                SignStack.push(w);
            }
            else {
                SignStack.push(w);
            }
        }
    }
    while (!SignStack.empty()) {
        if (SignStack.top().sign != '#') {
            ans.push_back(SignStack.top());
        }
        SignStack.pop();
    }
    return ans;
}

Postfix expression computing

In the postfix expression calculation, pressed into a digital reading to a digital stack, read the operator, two elements removed from the data stack is calculated, the calculated result onto the stack back to digital, after the element portion is completely read, is the number of elements in the stack operation result.

double Calculatoin(vector<Word> paword) {
    stack<double> ans;
    for (Word w : paword) {
        if (w.flag) {
            ans.push(w.num);
        }
        else {
            double a, b;
            b = ans.top(); ans.pop();
            a = ans.top(); ans.pop();
            switch (w.sign) {
            case '+':
            ans.push(a + b);
            break;
            case '-':
            ans.push(a - b);
            break;
            case '*':
            ans.push(a * b);
            break;
            case '/':
            ans.push(a / b);
            break;
            case '^':
            ans.push(pow(a, b));
            break;
            }
        }
    }
    return ans.top();
}

Please click on the link below the complete code:
complete code Github link

If there are omissions code, please indicate in the comments area, we welcome the discussion message.
Released nine original articles · won praise 2 · Views 319

Guess you like

Origin blog.csdn.net/Z_Pythagoras/article/details/104743280