自上而下和自下而上的语法有什么区别?一个例子很棒。
答案 0 :(得分:8)
首先,语法本身不是自上而下或自下而上的,解析器是(尽管有一些语法可以由一个语法解析而不是另一个语法)。
从实际的角度来看,主要区别在于大多数手写解析器是自上而下的,而机器生成的解析器的百分比是自下而上的(当然,反过来当然是可能的)。
自上而下的解析器通常使用递归下降,这通常意味着类似这样的结构(使用典型的数学表达式作为示例):
expression() { term() [-+] expression }
term() { factor() [*/] term() }
factor() { operand() | '(' expression() ')' }
自下而上的解析器反向工作 - 递归下降解析器从完整表达式开始,并将其分解为越来越小的片段,直到达到单个标记的级别,自下而上的解析器启动来自单个标记,并使用关于这些标记如何组合到表达层次结构的更高和更高级别的规则表,直到它达到顶级(上面表示为“表达式”)。
编辑:为了澄清,或许添加一个非常简单的解析器是有意义的。在这种情况下,我将完成将典型数学表达式的简化版本从中缀转换为后缀的旧经典:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void expression(void);
void show(int ch) {
putchar(ch);
putchar(' ');
}
int token() {
int ch;
while (isspace(ch=getchar()))
;
return ch;
}
void factor() {
int ch = token();
if (ch == '(') {
expression();
ch = token();
if (ch != ')') {
fprintf(stderr, "Syntax error. Expected close paren, found: %c\n", ch);
exit(EXIT_FAILURE);
}
}
else
show(ch);
}
void term() {
int ch;
factor();
ch = token();
if (ch == '*' || ch == '/') {
term();
show(ch);
}
else
ungetc(ch, stdin);
}
void expression() {
int ch;
term();
ch = token();
if (ch == '-' || ch=='+') {
expression();
show(ch);
}
else
ungetc(ch, stdin);
}
int main(int argc, char **argv) {
expression();
return 0;
}
请注意,这里的lexing非常愚蠢(它基本上只接受一个字符作为标记)并且允许的表达式非常有限(仅限+ - * /)。 OTOH,它足以处理如下输入:
1 + 2 *(3 + 4 *(5/6))
它确实产生了我认为正确的输出:
1 2 3 4 5 6 / * + * +
答案 1 :(得分:4)
Afaik它对语法本身没有任何影响,但为解析器做了。
维基百科对bottom-up和top-down parsing都有很长的解释。
一般来说,(imho)更直观的方式是自上而下。您从开始符号开始并应用适合的转换规则,而自下而上则需要应用转换规则向后(这通常会让我非常头疼)。