我一直在尝试在野牛工作中使用一个简单的计算器,但我得到了减少问题。
你能告诉我我做错了吗。
%{
#include <cstdio>
#include <iostream>
using namespace std;
// stuff from flex that bison needs to know about:
extern "C" int yylex();
extern "C" int yyparse();
extern "C" FILE *yyin;
void yyerror(const char *s);
%}
// Bison fundamentally works by asking flex to get the next token, which it
// returns as an object of type "yystype". But tokens could be of any
// arbitrary data type! So we deal with that in Bison by defining a C union
// holding each of the types of tokens that Flex could return, and have Bison
// use that union instead of "int" for the definition of "yystype":
%union {
int ival;
float fval;
char *sval;
}
// define the "terminal symbol" token types I'm going to use (in CAPS
// by convention), and associate each with a field of the union:
%token <fval> NUM
%token <sval> STRING
/* Define the type of node our nonterminal symbols represent.
The types refer to the %union declaration above. Ex: when
we call an ident (defined by union type ident) we are really
calling an (NIdentifier*). It makes the compiler happy.
*/
%type <fval> statement
%type <fval> statements
/* Operator precedence for mathematical operators */
%left TPLUS TMINUS
%left TMUL TDIV
%left UMINUS
%right TEXP
/* The Start*/
%start program
%%
// this is the actual grammar that bison will parse, but for right now it's just
// something silly to echo to the screen what bison gets from flex. We'll
// make a real one shortly:
program: statements
;
statements: statement
| statements statement
;
statement: NUM { $$ = $1; }
| statement TPLUS statement { $$ = $1 + $3; }
| statement TMINUS statement { $$ = $1 - $3; }
| statement TMUL statement { $$ = $1 * $3; }
| statement TDIV statement { $$ = $1 / $3; }
| TMINUS statement %prec UMINUS { $$ = -$2; }
| statement TEXP statement { $$ = pow($1, $3); }
| '(' statement ')' { $$ = $2; }
;
%%
int main() {
// open a file handle to a particular file:
FILE *myfile = fopen("Program.gb", "r");
// make sure it is valid:
if (!myfile) {
cout << "I can't open Program.gb" << endl;
return -1;
}
// set flex to read from it instead of defaulting to STDIN:
yyin = myfile;
// parse through the input until there is no more:
do {
yyparse();
} while (!feof(yyin));
return 0;
}
void yyerror(const char *s) {
cout << "EEK, parse error! Message: " << s << endl;
// might as well halt now:
exit(-1);
}
答案 0 :(得分:2)
要将@ rici的评论转换为答案,问题只在于您所定义的语法含糊不清。解决这个问题的一种方法是引入行尾标记。为了使它有点C风格,你可以这样做:
statements: statement ';'
| statements statement ';'
;
显然,如果词法分析器没有传回分号字符,则需要对词法分析器进行匹配更改。
您可能还会发现this question有助于解释转移 - 减少冲突是什么以及它们发生的原因。