2016-11-17 8 views
0

Also meine Grammatik unten 'funktioniert'. Allerdings hat es eine kleine Einschränkung jetzt kann ich Sachen machen wieBison Grammatik für grundlegende Rechner Ausgabe

1.0-----------------2.0 

und es wird Flop Flip zwischen 2 und -2 bis sie dann auswerten wird auf 1 op 2 bekommen. Bison noch neu und unklar, wie es am besten ist, eine Lösung dafür zu implementieren. Ich habe eine Idee im Sinn, einen Fehler mit jeder Kombination von '+' '- in Schritten von 3 zu erzeugen, aber das sind 8 Grammatikregeln und ich bin mir nicht einmal sicher, wie man einen Fehler in Bison wirft. Ich kann mir vorstellen, dass es einen saubereren, verständlicheren Weg gibt, dies zu tun.

Flex Lexer

%option nounistd 
%option noyywrap 

%{ 
#include <io.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include "parser.tab.h" 
#define isatty _isatty 
#define fileno _fileno 
%} 

%% 
[ \t]+ 
\n {return '\n';} 
[0-9]+(\.[0-9]+)? {yylval.number=atof(yytext); return NUMBER;} 
. {return yytext[0];} 
%% 

Bison Grammar

%{ 
    #include <stdio.h> 
    #include <math.h> 
    extern int yylex(void); 
    int yyerror(const char* c) { printf("%s\n",c); return 0;} 
%} 

%union 
{ 
    double number; 
} 

%type <number> exp 
%token <number> NUMBER 

%left '+' '-' 
%left '*' '/' 
%right '^' 

%start commands 
%% 
commands 
    : /*empty*/ 
    | commands line 
    ; 

line 
    : '\n' 
    | exp '\n' {printf("=%f\n",$1);} 
    | error '\n' {printf("encountered an error!\n");} 
    ; 

exp 
    : NUMBER { $$ = $1;} 
    | exp '+' exp {$$ = $1 + $3;} 
    | exp '-' exp {$$ = $1 - $3;} 
    | exp '*' exp {$$ = $1 * $3;} 
    | exp '/' exp {$$ = $1/$3;} 
    | exp '^' exp {$$ = pow($1,$3);} 
    | '-' exp {$$ = -$2;} 
    | '+' exp {$$ = $2;} 
    | '(' exp ')' {$$ = $2;} 
    ; 
%% 
+0

Scheint, dass dies das richtige Verhalten für mich ist. Sind Sie sicher, dass dies ein Problem ist? Ich habe gerade Ihren Ausdruck in Python 2.7 ausprobiert und verhält sich genauso. –

+0

Es ist "richtiges Verhalten" gemäß der Grammatik, wenn es nicht für die Operatoren ++ oder - war. Ich würde es gerne "nicht das richtige Verhalten" machen, nur als Test, um zu sehen, wie man etwas komplexere Grammatikregeln implementiert. Leider machte meine Neuheit selbst diese einfache Aufgabe schwierig. Ich würde gerne eine Angemessenheit für die Grammatik durchsetzen. Ich fange tatsächlich an zu glauben, dass der Lexer darin einfacher sein könnte. Etwas wie [+ -] {3} {return ERROR;}. – user2927848

+0

Wie erhälst du tatsächlich einen Fehler in Bison? – user2927848

Antwort

3

Das ist richtig und das erwartete Verhalten für arithmetische Auswertung, und Sie werden feststellen, dass es identisch in jeder Sprache arbeitet, die nicht die -- nicht implementiert Dekrementierungsoperator.

Wenn Sie einen -- Operator haben, würden Sie normalerweise, dass mit der Regel in Ihrem Lexer implementieren wie:

"--" { return DECREMENT; } 

, die garantieren, dass a---b als "a" gelext, "-", „- "," b "und a----b als" a "," - "," - "," b ". (Letzteres ist ein Syntaxfehler.) Das ist ein Ergebnis der Regel "maximales Knabbern", die von den meisten Sprachstandards gefordert wird und von den meisten Scanner-Generatoren implementiert wird. (Das Schreiben von Code wird im Allgemeinen nicht empfohlen, aber verboten.)

In C können Sie nicht zwei aufeinanderfolgende Post-Dekrement-Operatoren verwenden, da ein Post-Dekrement-Ausdruck kein Lvalue ist. Dies kann in der Grammatik erzwungen werden, indem das Argument von Operatoren vor und nach Dekrement und Inkrementieren zu einem L-Wert wird. Aber in C++ kann man die Korrektheit nicht einfach syntaktisch bestimmen; Obwohl es ein schrecklicher Stil wäre, hindert Sie nichts daran, operator--(int) für einen Typ zu überladen, um eine Referenz zurückzugeben.

Wenn Sie eine Sprache ohne Dekrementoperator haben, aber Sie wollen, aus irgendeinem ästhetischen Grund, auf Ausdrücke mit zwei aufeinander folgenden unären Operatoren zu verbieten, dann können Sie das auf die gleiche Art und Weise tun, wie oben angedeutet, zB .:

value: NUMBER | '(' expr ')' 
term: value | '-' value | '+' value 
expr: term | expr '-' expr | expr '+' expr | expr '*' expr | expr '/' expr | ... 

Hier können Sie nicht haben --a (oder -+a), weil ein unärer Operator kann nur auf eine value angewendet werden und ein value kann nicht mit einem unären Operator beginnen. Der Endbenutzer würde daher gezwungen sein, Klammern zu verwenden. Aber Sie sollten zumindest eine befriedigende Antwort für den Endnutzer bereithalten, der wissen möchte, warum Sie diese Einschränkung für notwendig halten.