Flex&Bison:打印分析树

时间:2018-10-12 23:02:23

标签: syntax tree bison flex-lexer yacc

基本上,我需要为C-编写编译器,但是我们需要5个步骤。步骤之一是将BNF语法转换为野牛,然后用已编译的内容打印树。让我解释一下:

BNF语法

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

文件:Project.fl

%option noyywrap

%{
    /* Definitions and statements */
    #include <stdio.h>
    #include "project.tab.h"

    int nlines = 1;
    char filename[50];
%}

ID      {letter}{letter}*
NUM     {digit}{digit}*
letter  [a-zA-Z]
digit   [0-9]

%%
"if"            { return T_IF;      }
"else"          { return T_ELSE;    }
"int"           { return T_INT;     }
"return"        { return T_RETURN;  }
"void"          { return T_VOID;    }
"while"         { return T_WHILE;   }
"+"             { return yytext[0]; }
"-"             { return yytext[0]; }
"*"             { return yytext[0]; }
"/"             { return yytext[0]; }
">"             { return T_GREAT;   }
">="            { return T_GREATEQ; }
"<"             { return T_SMALL;   }
"<="            { return T_SMALLEQ; }
"=="            { return T_COMPARE; }
"!="            { return T_NOTEQ;   }
"="             { return yytext[0]; }
";"             { return yytext[0]; }
","             { return yytext[0]; }
"("             { return yytext[0]; }
")"             { return yytext[0]; }
"["             { return yytext[0]; }
"]"             { return yytext[0]; }
"{"             { return yytext[0]; }
"}"             { return yytext[0]; }
(\/\*(ID)\*\/)  { return T_COMM;    }

{ID}            { return T_ID;      }
{NUM}           { return T_NUM;     }


\n              { ++nlines;         }
%%

文件:project.y

%{
    #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;
}

我已经将BNF语法转换为实际的.y文件,但是在打印出消息应准确到达的位置时遇到了问题。通常,语法会完成“然后”打印。

1 个答案:

答案 0 :(得分:1)

您呈现的期望输出是对分析树进行预排序的结果。

但是,bison会生成一个自底向上的解析器,该解析器在节点的子树完成时对解析树中的节点执行语义操作。因此,在语义动作中打印节点会产生一个后序遍历。我想这就是你最后一句话的意思。

尽管存在多种可能的解决方案,但最简单的解决方案可能是在解析过程中构造一个解析树,然后在解析结束时将其打印出来。 (您可以在语义动作中打印树以用于开始生产,但这有时会导致为错误输入而打印解析树。更好的方法是返回解析树的根,并在验证后从主程序打印它解析成功。)

我不知道“构建解析树”在您的项目的预期进度中适合什么位置。解析树在大多数应用程序中几乎没有用。更常见的是抽象语法树(AST)的构造,它省略了解析中的许多不相关的细节(例如单元产品)。您可以从解析树构造AST,但通常在解析操作中直接构造AST更为简单:代码看起来非常相似,但它的数量很少,这恰恰是因为不必为单位生产而构建树节点。