基本计算器问题的野牛语法

时间:2016-11-17 17:34:31

标签: c parsing bison flex-lexer

所以我的语法下面'有效'。但是,它有一个小警告,现在我可以做像

这样的事情
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;}
    ;
%%

1 个答案:

答案 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),因为一元运算符只能应用于valuevalue不能以一元运算符开头。因此最终用户将被迫使用括号。但是你应该至少为最终用户准备一个满意的答案,他们想知道为什么你认为有必要施加这种限制。