2015-06-26 6 views
0

В настоящее время я играю с Flex и Bison в первый раз. Я прочитал о контекстуальном приоритете на Bison manual page. Попытался создать минимальный пример, не используя директиву %prec, поскольку я не знаю, что он на самом деле делает. Вот мой минимальный пример.Bison - когда действительно необходимо для унарных операторов?

Flex файл

%option noyywrap 
%{ 
#include <iostream> 
#include "parser.h" 

int lineNum = 1; 
%} 

%% 

[ \t]+   ; 
\n    { lineNum++; } 
\/\/(.*)  ; 
"+"    { return PLUS; } 
"-"    { return MINUS; } 
"*"    { return MULTIPLY; } 

[0-9]+   { 
        yylval.int_val = atoi(yytext); 
        return INT; 
       } 

.    { std::cout << "Unknown token " << yytext << " at line " << lineNum << std::endl; yyterminate(); } 

%% 

Bison файл

%{ 
#include <iostream> 
#include <string> 

extern int lineNum; 
extern int yylex(); 
void yyerror(const char* e) { std::cerr << "ERROR ON LINE " << lineNum << ": " << e << std::endl; } 

extern int eval; 
%} 

%union 
{ 
    int int_val; 
} 

%define parse.error verbose 

%token <int_val> INT PLUS MINUS MULTIPLY 

%type <int_val> expr 

%left PLUS MINUS 
%left MULTIPLY 

%start expr 

%% 

expr : expr PLUS expr { $$ = $1 + $3; eval = $$; } 
     | expr MINUS expr { $$ = $1 - $3; eval = $$; } 
     | expr MULTIPLY expr { $$ = $1 * $3; eval = $$; } 
     | MINUS expr { $$ = -$2; eval = $$; } 
     | INT 
     ; 

%% 

Главная CPP файл

#include <iostream> 

int eval = 0; 
extern int yyparse(); 

int main() 
{ 
    yyparse(); 
    std::cout << eval << std::endl; 
    return 0; 
} 

я не сделал d eep, но для каждой отдельной комбинации с использованием унарного минуса я мог придумать, я получил правильный результат. Мне просто повезло, или директива %prec нужна только в некоторых особых случаях? Кроме того, я был бы признателен, если потребуется директива, чтобы я мог самостоятельно оценивать сдвиги и сворачивать в стек.

Благодаря

+0

Он не дает правильного ответа для '-2 + 3'. – EJP

+0

Он делает, и я не вижу причин, почему это не должно. Как сказал Ричи, он не создает правильное дерево разбора, однако он дает правильный ответ. И исходя из того, что - и + имеют одинаковые приоритеты и остаются ассоциативными, этот даже создает правильное дерево разбора. –

ответ

1

Ваш код производит неправильный разбор, но правильный результат, так как унарный минус эквивалентно умножению на -1, а умножение ассоциативно. Поэтому, даже если он обрабатывает -2*3 как -(2*3) вместо (-2)*3, результирующее значение будет таким же.

В случае выражения типа -2-3, вы получите правильный разобрана, потому что вы объявили -, как быть левоассоциативные, поэтому (-2)-3 предпочтительнее -(2-3), так же, как (1-2)-3 бы предпочтительнее 1-(2-3).

Итак, когда вам не нужно объявлять приоритет для унарного минуса? Если

  • единственный оператор, который является как префикс и инфиксным является −

  • Каждый оператор ⊕ с более высоким приоритетом, чем (двоичный) −, − (б) = (− a) ⊕ b;

  • Вы не заботитесь о правильном дереве разбора.

Это работает для *, но в общем, не для (целое число) / и %.

+0

Спасибо за объяснение. Я почему-то не думал о неправильном дереве деривации. Я также нашел способ превратить зубров в режим отладки, и после того, как я увижу все, что происходит в стеке, я вижу разницу. Я попытаюсь использовать его, чтобы увидеть, как работает '% prec'. –