所以我的语法下面'有效'。但是,它有一个小警告,现在我可以做像
这样的事情1.0-----------------2.0
它将在2和-2之间翻转,直到达到1 op 2,然后进行评估。对野牛来说仍然是新手,并且不清楚如何最好地为此实施修复。我有一个想法,用'+'' - '的每个组合提出一个错误,增量为3,但这是8个语法规则,我甚至不确定如何在野牛中抛出错误。我想有一种更清晰,更容易理解的方法。
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 :(得分:3)
这是算术评估的正确和预期的行为,你会发现它在任何没有实现--
递减运算符的语言中都是相同的。
如果您有--
运算符,通常会在词法分析器中使用以下规则实现:
"--" { return DECREMENT; }
这将保证a---b
被列为&#34; a&#34;,&#34; - &#34;,&#34; - &#34;,&#34; b& #34;和a----b
as&#34; a&#34;,&#34; - &#34;,&#34; - &#34;,&#34; b&#34;。 (后者是语法错误。)这是&#34;最大咀嚼&#34;的结果。规则,这是大多数语言标准所要求的并且由大多数扫描仪生成器实现。 (编写这样的代码通常是不鼓励的,但不是禁止的。)
在C中,您不能使用两个连续的后递减运算符,因为后递减表达式不是左值。这可以通过要求前后递减和 - 增量运算符的参数为左值来在语法中强制执行。但是在C ++中,你无法在语法上轻松地确定正确性;虽然它会是一种可怕的风格,但是没有什么可以阻止你为某些类型重载operator--(int)
以返回引用。
如果您的语言没有递减运算符,但出于某些美学原因,您希望禁止使用两个连续一元运算符的表达式,那么您可以采用与上面提到的相同的方式执行此操作,例如:
value: NUMBER | '(' expr ')'
term: value | '-' value | '+' value
expr: term | expr '-' expr | expr '+' expr | expr '*' expr | expr '/' expr | ...
在这里,您不能拥有--a
(或-+a
),因为一元运算符只能应用于value
而value
不能以一元运算符开头。因此最终用户将被迫使用括号。但是你应该至少为最终用户准备一个满意的答案,他们想知道为什么你认为有必要施加这种限制。