Parsing 为什么与后缀表达式相比,编译器在解析中缀表达式时遇到困难?

Parsing 为什么与后缀表达式相比,编译器在解析中缀表达式时遇到困难?,parsing,data-structures,compiler-construction,postfix-notation,infix-notation,Parsing,Data Structures,Compiler Construction,Postfix Notation,Infix Notation,我在读编译器设计书,书中说“编译器在解决中缀表达式时有问题,因为它在确定操作数的优先级时有问题,所以应该始终将其转换为后缀,然后解析表达式” 为什么与后缀表达式相比,编译器在解析中缀表达式时遇到困难?考虑a+b*c/de。根据传统的优先规则,这应该被解析为a+((b*c)/d)。简单地从右向左读取将产生((a+b)*c)/d,这不是您想要的。编译器需要知道每个运算符的进位(和关联性),并将其考虑在内 另一方面,后缀表达式具有明确的优先级。例如,上面的第一个表达式相当于bc*d/a+ 我不确定我是

我在读编译器设计书,书中说“编译器在解决中缀表达式时有问题,因为它在确定操作数的优先级时有问题,所以应该始终将其转换为后缀,然后解析表达式”


为什么与后缀表达式相比,编译器在解析中缀表达式时遇到困难?考虑
a+b*c/de
。根据传统的优先规则,这应该被解析为
a+((b*c)/d)
。简单地从右向左读取将产生
((a+b)*c)/d
,这不是您想要的。编译器需要知道每个运算符的进位(和关联性),并将其考虑在内

另一方面,后缀表达式具有明确的优先级。例如,上面的第一个表达式相当于
bc*d/a+


我不确定我是否知道作者“应该始终将其转换为后缀,然后解析表达式”的意思,但这就是要点。(在我看来,转换为后缀已经需要解析)。

您可能认为编译器是一个问题,找出括号将去向何处。

考虑两个运算符,
*
+

如果你有中缀符号,你可以有如下语句

X = A * B + C
在不知道操作顺序的情况下,编译器可能会将其解释为

X = ( A * B ) + C

如果是用后固定符号写的,就没有环境影响。它就像旧的HP计算器。有一个堆栈,运算符从堆栈中弹出两个操作数,并将结果推回

因此,第一个公式看起来更像(忽略对X的赋值,从技术上讲是另一个操作符)

而第二个是

A B C + *

也就是说,您的陈述让我有点困惑,因为我认为从in-fix到post-fix是制作编译器的目的之一,而不是编译器所做的简单操作。对于递归下降解析器,中缀解析非常简单,如下所示的简短Java示例。类似的东西可以很容易地用于表达式树的生成

延迟到不同的阶段可能有很多意义,但我从未见过这样的情况:在构建解析树之前,这种重新排序作为对原始输入的转换有多大意义

也许这本书已经过时了?这句话出自哪本书

public class InfixProcessor {
  static final String[] OPERATORS = {"-+", "/*"};
  static StreamTokenizer tokenizer;

  static double process(String s) throws IOException {
    tokenizer = new StreamTokenizer(new StringReader(s));
    tokenizer.ordinaryChar('-');
    tokenizer.ordinaryChar('/');
    tokenizer.nextToken();
    return processInfix(0);
  }

  static double processInfix(int precedence) throws IOException {
    if (precedence >= OPERATORS.length) {
      return processPrimary();
    }
    double result = processInfix(precedence + 1);
    while (OPERATORS[precedence].indexOf((char) tokenizer.ttype) != -1) {
      int op = tokenizer.ttype;
      tokenizer.nextToken();
      double right = processInfix(precedence + 1);
      switch (op) {
        case '+': result += right; break;
        case '-': result -= right; break;
        case '*': result *= right; break;
        case '/': result /= right; break;
        default: throw new RuntimeException();
      }
    }
    return result;
  }

  static double processPrimary() throws IOException {
    if (tokenizer.ttype != StreamTokenizer.TT_NUMBER) {
      throw new RuntimeException("Number expected");
    }
    double result = tokenizer.nval;
    tokenizer.nextToken();
    return result;
  }

  public static void main(String[] args) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    while (true) {
      System.out.print("Expression> ");
      String expr = reader.readLine();
      if (expr == null || expr.isEmpty()) break;
      System.out.println("Result: " + process(expr));
    }
  }
}
编译器在解析前缀、中缀或后缀顺序的表达式时不会遇到任何问题。语法对于编译器来说很容易处理

不过,您不会看到很多编译器使用前缀或后缀符号。那是因为人们不习惯这样。几乎只有第四个家伙侥幸逃脱了后缀,他们的编译器几乎微不足道,这使得它非常适合运行在非常小的机器上。福斯程序员学会了热爱后缀,并凭借一点经验相处得很好

[我不知道是谁告诉我“你应该总是把它转换成后缀然后解析表达式”,但那是胡说八道]

A B C + *
public class InfixProcessor {
  static final String[] OPERATORS = {"-+", "/*"};
  static StreamTokenizer tokenizer;

  static double process(String s) throws IOException {
    tokenizer = new StreamTokenizer(new StringReader(s));
    tokenizer.ordinaryChar('-');
    tokenizer.ordinaryChar('/');
    tokenizer.nextToken();
    return processInfix(0);
  }

  static double processInfix(int precedence) throws IOException {
    if (precedence >= OPERATORS.length) {
      return processPrimary();
    }
    double result = processInfix(precedence + 1);
    while (OPERATORS[precedence].indexOf((char) tokenizer.ttype) != -1) {
      int op = tokenizer.ttype;
      tokenizer.nextToken();
      double right = processInfix(precedence + 1);
      switch (op) {
        case '+': result += right; break;
        case '-': result -= right; break;
        case '*': result *= right; break;
        case '/': result /= right; break;
        default: throw new RuntimeException();
      }
    }
    return result;
  }

  static double processPrimary() throws IOException {
    if (tokenizer.ttype != StreamTokenizer.TT_NUMBER) {
      throw new RuntimeException("Number expected");
    }
    double result = tokenizer.nval;
    tokenizer.nextToken();
    return result;
  }

  public static void main(String[] args) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    while (true) {
      System.out.print("Expression> ");
      String expr = reader.readLine();
      if (expr == null || expr.isEmpty()) break;
      System.out.println("Result: " + process(expr));
    }
  }
}