如何在 yacc 中合并 ++ 运算符

问题描述 投票:0回答:1

在经典的 Kernighan & Pike 书籍(UNIX 编程环境)的第 8 章中,将 hoc1 作为使用 yacc 的简单计算器的示例进行介绍。

本书建议改进源代码以涵盖酉增量运算符(++)。

我尝试在 yacc 源代码(包括 lex 函数并且不使用配套的 lex 程序)中实现 ++ 运算符,如下所示:

%{
#define YYSTYPE double          /* DATA TYPE OF YACC STACK */ 
%}

%token NUMBER
%left '+' '-'                   /* LEFT ASSOCIATIVE, SAME PRECEDENCE */ 
%left '*' '/'                   /* LEFT ASSOC., HIGHER PRECEDENCE */ 
%left UNARYMINUS                /* LEFT ASSOC., HIGHER PRECEDENCE */ 
%right INC

/* GRAMMAR */

%% 
list:     /* nothing */ 
        | list '\n' 
        | list expr '\n'        { printf("\t%.8g\n", $2); } 

expr:     NUMBER                        { $$ = $1; } 
        | expr INC                      { $$ = $1 + 1; } 
        | '-' expr %prec UNARYMINUS     { $$ = -$2; }
        | expr '+' expr                 { $$ = $1 + $3; } 
        | expr '-' expr                 { $$ = $1 - $3; } 
        | expr '*' expr                 { $$ = $1 * $3; } 
        | expr '/' expr                 { $$ = $1 / $3; } 
        | expr '%' expr                 { $$ = fmod($1, $3); } 
        | '(' expr ')'                  { $$ = $2; }
%% 

/* GRAMMAR PROCESSING ROUTINES */

#include <stdio.h>
#include <ctype.h>
#include <math.h>

int yylex(void);
void yyerror(char *s);
void warning(char *s, char *t);

char    *progname;
int     lineno = 1;

int main(int argc, char *argv[]) {

        progname = argv[0];
        yyparse();
}

int yylex() {
        int c;

        while((c=getchar()) == ' ' || c == '\t')
                ;

        if(c==EOF) {
                return 0;
        }
        if(c=='.' || isdigit(c)) {
                ungetc(c,stdin);
                scanf("%lf", &yylval);
                return NUMBER;
        }
        if(c=='+') {
                if((c=getchar()) == '+') {
                        return INC;
                } else {
                        ungetc(c,stdin);
                        return '+';
                }
        }
        if(c=='\n')
                lineno++;
        return c;
}

void yyerror(char *s) {
        warning(s, (char *)0);
}

void warning(char *s, char *t) {
        fprintf(stderr, "%s: %s", progname, s);
        if(t) {
                fprintf(stderr, " %s", t);
        }
        fprintf(stderr, " near line %d\n", lineno);
}

首先,我使用 yacc 生成 C 源代码,并且得到了移位/归约冲突,为什么会出现这些移位/归约冲突?

$ make
yacc -d hoc1.y
yacc: 11 shift/reduce conflicts.
c yacc lex
1个回答
0
投票

移位/归约冲突全部来自不明确的

'%'
运算符,因为您没有为其指定优先级或关联性。如果您将其添加到优先级规则中(与
'*'
'/
' 相同的优先级),它们将会消失:

%left '*' '/' '%'              /* LEFT ASSOC., HIGHER PRECEDENCE */
© www.soinside.com 2019 - 2024. All rights reserved.