Shunting+yard -- RPN 算法






C \Code 

/* 当前日期: 2008-09-07 星期日 */

#include <string.h>
#include <stdio.h>
#define bool int
#define false 0
#define true 1

// operators
// precedence   operators       associativity
// 1            !               right to left
// 2            * / %           left to right
// 3            + -             left to right
// 4            =                right to left
int op_preced(const char c)
{
    switch(c)    {
        case '!':
            return 4;
        case '*':  case '/': case '%':
            return 3;
        case '+': case '-':
            return 2;
        case '=':
            return 1;
    }
    return 0;
}

bool op_left_assoc(const char c)
{
    switch(c)    {
        // left to right
        case '*': case '/': case '%': case '+': case '-':
            return true;
        // right to left
        case '=': case '!':
            return false;
    }
    return false;
}

unsigned int op_arg_count(const char c)
{
    switch(c)  {
        case '*': case '/': case '%': case '+': case '-': case '=':
            return 2;
        case '!':
            return 1;
        default:
            return c - 'A';
    }
    return 0;
}

#define is_operator(c)  (c == '+' || c == '-' || c == '/' || c == '*' || c == '!' || c == '%' || c == '=')
#define is_function(c)  (c >= 'A' && c <= 'Z')
#define is_ident(c)     ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))

bool shunting_yard(const char *input, char *output)
{
    const char *strpos = input, *strend = input + strlen(input);
    char c, *outpos = output;

    char stack[32];       // operator stack
    unsigned int sl = 0;  // stack length
    char     sc;          // used for record stack element

    while(strpos < strend)   {
        // read one token from the input stream
        c = *strpos;
        if(c != ' ')    {
            // If the token is a number (identifier), then add it to the output queue.
            if(is_ident(c))  {
                *outpos = c; ++outpos;
            }
            // If the token is a function token, then push it onto the stack.
            else if(is_function(c))   {
                stack[sl] = c;
                ++sl;
            }
            // If the token is a function argument separator (e.g., a comma):
            else if(c == ',')   {
                bool pe = false;
                while(sl > 0)   {
                    sc = stack[sl - 1];
                    if(sc == '(')  {
                        pe = true;
                        break;
                    }
                    else  {
                        // Until the token at the top of the stack is a left parenthesis,
                        // pop operators off the stack onto the output queue.
                        *outpos = sc;
                        ++outpos;
                        sl--;
                    }
                }
                // If no left parentheses are encountered, either the separator was misplaced
                // or parentheses were mismatched.
                if(!pe)   {
                    printf("Error: separator or parentheses mismatched\n");
                    return false;
                }
            }
            // If the token is an operator, op1, then:
            else if(is_operator(c))  {
                while(sl > 0)    {
                    sc = stack[sl - 1];
                    // While there is an operator token, o2, at the top of the stack
                    // op1 is left-associative and its precedence is less than or equal to that of op2,
                    // or op1 is right-associative and its precedence is less than that of op2,
                    if(is_operator(sc) &&
                        ((op_left_assoc(c) && (op_preced(c) <= op_preced(sc))) ||
                           (!op_left_assoc(c) && (op_preced(c) < op_preced(sc)))))   {
                        // Pop o2 off the stack, onto the output queue;
                        *outpos = sc;
                        ++outpos;
                        sl--;
                    }
                    else   {
                        break;
                    }
                }
                // push op1 onto the stack.
                stack[sl] = c;
                ++sl;
            }
            // If the token is a left parenthesis, then push it onto the stack.
            else if(c == '(')   {
                stack[sl] = c;
                ++sl;
            }
            // If the token is a right parenthesis:
            else if(c == ')')    {
                bool pe = false;
                // Until the token at the top of the stack is a left parenthesis,
                // pop operators off the stack onto the output queue
                while(sl > 0)     {
                    sc = stack[sl - 1];
                    if(sc == '(')    {
                        pe = true;
                        break;
                    }
                    else  {
                        *outpos = sc;
                        ++outpos;
                        sl--;
                    }
                }
                // If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
                if(!pe)  {
                    printf("Error: parentheses mismatched\n");
                    return false;
                }
                // Pop the left parenthesis from the stack, but not onto the output queue.
                sl--;
                // If the token at the top of the stack is a function token, pop it onto the output queue.
                if(sl > 0)   {
                    sc = stack[sl - 1];
                    if(is_function(sc))   {
                        *outpos = sc;
                        ++outpos;
                        sl--;
                    }
                }
            }
            else  {
                printf("Unknown token %c\n", c);
                return false; // Unknown token
            }
        }
        ++strpos;
    }
    // When there are no more tokens to read:
    // While there are still operator tokens in the stack:
    while(sl > 0)  {
        sc = stack[sl - 1];
        if(sc == '(' || sc == ')')   {
            printf("Error: parentheses mismatched\n");
            return false;
        }
        *outpos = sc;
        ++outpos;
        --sl;
    }
    *outpos = 0; // Null terminator
    return true;
}

bool execution_order(const char *input) {
    printf("order: (arguments in reverse order)\n");
    const char *strpos = input, *strend = input + strlen(input);
    char c, res[4];
    unsigned int sl = 0, sc, stack[32], rn = 0;
        // While there are input tokens left
    while(strpos < strend)  {
                // Read the next token from input.
        c = *strpos;
                // If the token is a value or identifier
        if(is_ident(c))    {
                        // Push it onto the stack.
            stack[sl] = c;
            ++sl;
        }
                // Otherwise, the token is an operator  (operator here includes both operators, and functions).
        else if(is_operator(c) || is_function(c))    {
                        sprintf(res, "_%02d", rn);
                        printf("%s = ", res);
                        ++rn;
                        // It is known a priori that the operator takes n arguments.
                        unsigned int nargs = op_arg_count(c);
                        // If there are fewer than n values on the stack
                        if(sl < nargs) {
                                // (Error) The user has not input sufficient values in the expression.
                                return false;
                        }
                        // Else, Pop the top n values from the stack.
                        // Evaluate the operator, with the values as arguments.
                        if(is_function(c)) {
                                printf("%c(", c);
                                while(nargs > 0) {
                                        sc = stack[sl - 1];
                                        sl--;
                                        if(nargs > 1)    {
                                                printf("%s, ", &sc);
                                        }
                                        else {
                                                printf("%s)\n",&sc);
                                        }
                                        --nargs;
                                }
                        }
                        else   {
                                if(nargs == 1) {
                                        sc = stack[sl - 1];
                                        sl--;
                                        printf("%c %s;\n", c, &sc);
                                }
                                else   {
                                        sc = stack[sl - 1];
                                        sl--;
                                        printf("%s %c ", &sc, c);
                                        sc = stack[sl - 1];
                                        sl--;
                                        printf("%s;\n",&sc);
                                }
                        }
                        // Push the returned results, if any, back onto the stack.
            stack[sl] = *(unsigned int*)res;
            ++sl;
        }
        ++strpos;
    }
        // If there is only one value in the stack
        // That value is the result of the calculation.
        if(sl == 1) {
                sc = stack[sl - 1];
                sl--;
                printf("%s is a result\n", &sc);
                return true;
        }
        // If there are more values in the stack
        // (Error) The user input has too many values.
        return false;
}

int main() {
    // functions: A() B(a) C(a, b), D(a, b, c) ...
    // identifiers: 0 1 2 3 ... and a b c d e ...
    // operators: = - + / * % !
    const char *input = "a = D(f - b * c + d, !e, g)";
    //const char *input = "a*(((b+c)*d-e+)/g-h)+i*j";
    char output[128];
    printf("input: %s\n", input);
    if(shunting_yard(input, output))    {
        printf("output: %s\n", output);
        if(!execution_order(output))
            printf("\nInvalid input\n");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Java代码实现一个基础计算器,支持加、减、乘、除、取模和括号运算: ```java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Calculator extends JFrame implements ActionListener { private JTextField displayTextField; public Calculator() { super("简易计算器"); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); displayTextField = new JTextField(); displayTextField.setEditable(false); mainPanel.add(displayTextField, BorderLayout.NORTH); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(4, 4)); String[] buttonLabels = {"7", "8", "9", "/", "4", "5", "6", "*", "1", "2", "3", "-", "0", ".", "=", "+"}; for (int i = 0; i < buttonLabels.length; i++) { JButton button = new JButton(buttonLabels[i]); button.addActionListener(this); buttonPanel.add(button); } mainPanel.add(buttonPanel, BorderLayout.CENTER); setContentPane(mainPanel); } private String calculate(String expression) { // Check if expression is null or empty if (expression == null || expression.isEmpty()) { return "错误:表达式为空"; } // Check if expression contains only valid characters if (!expression.matches("[0-9+\\-*/%.()]+")) { return "错误:表达式包含无效字符"; } // Check if expression has balanced parentheses int parenthesesCount = 0; for (int i = 0; i < expression.length(); i++) { char c = expression.charAt(i); if (c == '(') { parenthesesCount++; } else if (c == ')') { parenthesesCount--; } if (parenthesesCount < 0) { return "错误:表达式包含未匹配的右括号"; } } if (parenthesesCount > 0) { return "错误:表达式包含未匹配的左括号"; } // Evaluate expression try { double result = evaluate(expression); return Double.toString(result); } catch (IllegalArgumentException e) { return "错误:" + e.getMessage(); } } private double evaluate(String expression) { Stack<Double> operands = new Stack<>(); Stack<Character> operators = new Stack<>(); int i = 0; while (i < expression.length()) { char c = expression.charAt(i); if (Character.isDigit(c) || c == '.') { StringBuilder operandBuilder = new StringBuilder(); while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) { operandBuilder.append(expression.charAt(i)); i++; } double operand = Double.parseDouble(operandBuilder.toString()); operands.push(operand); } else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%') { while (!operators.isEmpty() && hasHigherOrEqualPrecedence(c, operators.peek())) { evaluateTop(operands, operators); } operators.push(c); i++; } else if (c == '(') { operators.push(c); i++; } else if (c == ')') { while (!operators.isEmpty() && operators.peek() != '(') { evaluateTop(operands, operators); } if (operators.isEmpty()) { throw new IllegalArgumentException("表达式包含未匹配的右括号"); } operators.pop(); i++; } else { throw new IllegalArgumentException("表达式包含无效字符 " + c); } } while (!operators.isEmpty()) { evaluateTop(operands, operators); } if (operands.size() != 1 || !operators.isEmpty()) { throw new IllegalArgumentException("表达式无效"); } return operands.pop(); } private boolean hasHigherOrEqualPrecedence(char operator1, char operator2) { return (operator1 == '*' || operator1 == '/' || operator1 == '%') || (operator1 == '+' || operator1 == '-') && (operator2 == '+' || operator2 == '-'); } private void evaluateTop(Stack<Double> operands, Stack<Character> operators) { double operand2 = operands.pop(); double operand1 = operands.pop(); char operator = operators.pop(); double result = applyOperator(operator, operand1, operand2); operands.push(result); } private double applyOperator(char operator, double operand1, double operand2) { switch (operator) { case '+': return operand1 + operand2; case '-': return operand1 - operand2; case '*': return operand1 * operand2; case '/': if (operand2 == 0) { throw new IllegalArgumentException("除数不能为零"); } return operand1 / operand2; case '%': if (operand2 == 0) { throw new IllegalArgumentException("除数不能为零"); } return operand1 % operand2; default: throw new IllegalArgumentException("无效操作符 " + operator); } } public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if (command.equals("=")) { String expression = displayTextField.getText(); String result = calculate(expression); displayTextField.setText(result); } else { displayTextField.setText(displayTextField.getText() + command); } } public static void main(String[] args) { Calculator calculator = new Calculator(); calculator.setSize(300, 400); calculator.setLocationRelativeTo(null); calculator.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); calculator.setVisible(true); } } ``` 该代码中使用了图形用户界面,包含数字、操作符和等号按钮,以及一个文本框来显示表达式和结果。当用户点击等号按钮时,程序会调用 `calculate` 方法来计算表达式的值,然后将结果显示在文本框中。 `calculate` 方法使用栈来处理表达式,首先检查表达式的合法性,然后使用 Dijkstra's Shunting Yard Algorithm 将中缀表达式转换为后缀表达式,并计算结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值