Syntax Flex&;Bison:打印解析树
基本上,我有一个任务,我需要为C-做一个编译器,但我们要分5个步骤来完成。其中一个步骤是将BNF语法转换为bison,然后打印一个包含已编译内容的树。让我解释一下: BNF语法Syntax Flex&;Bison:打印解析树,syntax,tree,bison,flex-lexer,yacc,Syntax,Tree,Bison,Flex Lexer,Yacc,基本上,我有一个任务,我需要为C-做一个编译器,但我们要分5个步骤来完成。其中一个步骤是将BNF语法转换为bison,然后打印一个包含已编译内容的树。让我解释一下: BNF语法 1. program→declaration-list 2. declaration-list→declaration-list declaration | declaration 3. var-declaration| fun-declaration 4. var-declaration→type-specifierI
1. program→declaration-list
2. declaration-list→declaration-list declaration | declaration
3. var-declaration| fun-declaration
4. var-declaration→type-specifierID;| type-specifierID[NUM];
5. type-specifier→int | void
6. fun-declaration→type-specifierID(params)compound-stmt
7. params→param-list| void
8. param-list→param-list,param | param
9. param→type-specifierID | type-specifierID[]
10. compound-stmt→{local-declarations statement-list}
11. local-declarations→local-declarations var-declaration| empty
12. statement-list→statement-list statement| empty
13. statement→expression-stmt| compound-stmt| selection-stmt | iteration-stmt | return-stmt
14. expession-stmt→expression;| ;
15. selection-stmt→if(expression)statement| if(expression) statement else statement
16. iteration-stmt→while(expression)statement
17. return-stmt→return; | return expression;
18. expression→var=expression| simple-expression
19. var→ID| ID[expression]
20. simple-expression→additive-expression relop additive-expression| additive-expression
21. relop→<=| <| >| >=| ==| !=
22. additive-expression→additive-expression addop term| term
23. addop→+| -
24. term→term mulop factor| factor
25. mulop→*| /
26. factor→(expression)| var| call| NUM
27. call→ID(args)
28. args→arg-list| empty
29. arg-list→arg-list,expression| expression
基于树的示例代码
/* A program */
void main(void)
{
int x; int y;
x = input();
y = x + 5;
}
我已将BNF语法转换为实际的.y文件,但在打印出消息的确切位置时遇到了问题。通常,一本语法书会在完成后打印出来 您呈现的所需输出是解析树的预排序遍历的结果 但是,bison生成一个自底向上的解析器,当节点的子树完成时,该解析器为解析树中的节点执行语义操作。因此,在语义操作中打印节点会生成一个后序遍历。我想这就是你最后一句话的意思 虽然有各种可能的解决方案,但最简单的可能是在解析过程中构造解析树,然后在解析结束时打印出来。(您可以在开始生产的语义操作中打印树,但这有时会导致打印错误输入的解析树。最好是返回解析树的根,并在验证解析成功后从主程序打印它。)
我不知道“构造一个解析树”在你的项目预期进展中的位置。解析树在大多数应用程序中几乎没有用处。更常见的是抽象语法树(AST)的构造,它从解析中省略了许多不相关的细节(如单元生成)。您可以从解析树构造AST,但通常在解析操作中直接构造AST更简单:代码看起来非常相似,但实际上很少,因为不必为单元生产构建树节点。嘿,感谢您的回复!很难理解你的答案,但我正在努力!你能给我一个类似的解决方案吗?该项目由5个部分组成,第一部分是在.fl文件中编写一些正则表达式,查找C的“if”、“else”、“;”等,并返回一个句子“find an”if“on line.#”。现在,第二部分是在.y文件中编写bnf语法(猜测这是正确的术语),但现在在查找特定代码时打印输出。我已经研究过AST,但我认为这不是我需要的。@pigufilms:如果你只是在该产品的语义动作中打印每个产品,你会发现该产品遵循其组成部分。这就是自底向上解析的本质。也许这就是你的教授想要的;我不知道。但是如果你想按你指定的顺序打印,你需要建立一棵树,然后遍历它。我想打印我指定的顺序。基本上,如果你仔细观察它,不管它是什么语法,它都会立即执行一个代码(在我的例子中是printf)。但我正在努力解决这个问题,因为它没有按我希望的那样工作。@PiguFilms:它按我声明的顺序打印,因为这是自底向上解析的本质。一旦您了解了它为什么按顺序打印,您就会了解自底向上解析是如何工作的。这是一个有用的教训。但是让它按您希望的顺序打印意味着保存解析树。如果,就像你说的,你仔细看。呃,似乎找不到可能的答案。尝试用不同的变量保存解析树,并自己“制作”树,但没有成功。有什么提示吗?
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern int yyparse();
void yyerror(const char* s);
%}
%token T_IF T_ELSE T_INT T_RETURN T_VOID T_WHILE
T_GREAT T_GREATEQ T_SMALL T_SMALLEQ T_COMPARE T_NOTEQ
T_COMM T_ID T_NUM
%%
program: declaration-list { printf("program"); }
;
declaration-list: declaration-list declaration
| declaration
;
declaration: var-declaration
| fun-declaration
;
var-declaration: type-specifier T_ID ';'
| type-specifier T_ID'['T_NUM']' ';'
;
type-specifier: T_INT
| T_VOID
;
fun-declaration: type-specifier T_ID '('params')' compound-stmt
;
params: param-list
| T_VOID
;
param-list: param-list',' param
| param
;
param: type-specifier T_ID
| type-specifier T_ID'['']'
;
compound-stmt: '{' local-declarations statement-list '}'
;
local-declarations: local-declarations var-declaration
|
;
statement-list: statement-list statement
|
;
statement: expression-stmt
| compound-stmt
| selection-stmt
| iteration-stmt
| return-stmt
;
expression-stmt: expression ';'
| ';'
;
selection-stmt: T_IF '('expression')' statement
| T_IF '('expression')' statement T_ELSE statement
;
iteration-stmt: T_WHILE '('expression')' statement
;
return-stmt: T_RETURN ';'
| T_RETURN expression ';'
;
expression: var '=' expression
| simple-expression
;
var: T_ID { printf("\nterm\nfactor_var\nvar(x)"); }
| T_ID '['expression']'
;
simple-expression: additive-expression relop additive-expression
| additive-expression
;
relop: T_SMALLEQ
| T_SMALL
| T_GREAT
| T_GREATEQ
| T_COMPARE
| T_NOTEQ
;
additive-expression: additive-expression addop term
| term
;
addop: '+' { printf("\naddop(+)"); }
| '-' { printf("\naddop(-)"); }
;
term: term mulop factor
| factor
;
mulop: '*' { printf("\nmulop(*)"); }
| '/' { printf("\nmulop(/)"); }
;
factor: '('expression')' { printf("\nfactor1"); }
| var
| call
| T_NUM { printf("\nterm\nfactor(5)"); }
;
call: T_ID '('args')' { printf("\ncall(input)"); }
;
args: arg-list
| { printf("\nargs(empty)"); }
;
arg-list: arg-list',' expression
| expression
;
%%
int main(void) {
return yyparse();
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
exit(1);
}
program
declaration_list
declaration
fun_definition(VOID-main)
params_VOID-compound
params(VOID)
compound_stmt
local_declarations
local_declarations
local_declarations(empty)
var_declaration(x)
type_specifier(INT)
var_declaration(y)
type_specifier(INT)
statement_list
statement_list
statement_list(empty)
statement
expression_stmt
expression
var(x)
expression
simple_expression
additive_expression
term
factor
call(input)
args(empty)
statement
expression_stmt
expression
var(y)
expression
simple_expression
additive_expression(ADDOP)
additive_expression
term
factor_var
var(x)
addop(+)
term
factor(5)
/* A program */
void main(void)
{
int x; int y;
x = input();
y = x + 5;
}