Flex & Bison: печать дерева разбора - PullRequest
0 голосов
/ 13 октября 2018

По сути, у меня есть задание, в котором мне нужно сделать компилятор для C-, но мы делаем это в 5 шагов.Одним из шагов было превратить грамматику 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 голосов
/ 13 октября 2018

Требуемый вывод, который вы представляете, является результатом обхода дерева разбора по предварительному порядку.

Однако bison генерирует синтаксический анализатор снизу вверх, который выполняет семантические действия для узла в дереве разбора, когдаподдерево узла завершено.Таким образом, печать узла в семантическом действии приводит к обходу после заказа.Я полагаю, это то, что вы подразумеваете под своим последним предложением.

Хотя существует множество возможных решений, наиболее простым из них, вероятно, является построение дерева разбора во время разбора, а затем распечатка его в концеразобрать.(Вы можете напечатать дерево в семантическом действии для начала производства, но это иногда приводит к печати дерева разбора для ошибочного ввода. Лучше вернуть корень дерева разбора и распечатать его из основной программы после проверкичто анализ был успешным.)

Я не знаю, где «построить дерево синтаксического анализа» вписывается в ожидаемую прогрессию вашего проекта.Деревья разбора малопригодны в большинстве приложений.Гораздо более распространенным является построение абстрактного синтаксического дерева (AST), которое исключает многие несущественные подробности из анализа (например, создание единиц).Вы можете построить AST из дерева разбора, но обычно проще создать его непосредственно в действиях разбора: код выглядит очень похоже, но его меньше точно, потому что узлы дерева не должны быть построены для единичных производств.

...