1
votes

I am trying to enforce some parsing errors by defining a non-associative precedence. Here is part of my grammar file:

Comparison :
    Value ComparisonOp Value 
    {
        $2->Left($1);
        $2->Right($3);
        $$ = $2;
    } 
    ;

Expressions like 1 = 2 should parse, but expressions like 1 = 2 = 3 are not allowed in the grammar. To accommodate this, I tried to make my operator non associative as follows:

%nonassoc NONASSOCIATIVE
.
.(rest of the grammar)
.
Comparison :
    Value ComparisonOp Value %prec NONASSOCIATIVE
    {
        $2->Left($1);
        $2->Right($3);
        $$ = $2;
    } 
    ;

1 = 2 = 3 still passes, Could someone please tell me what I am doing wrong?

1

1 Answers

3
votes

You need to set the associativity of the ComparisonOp token(s). Either

%nonassoc ComparisonOp NONASSOCIATIVE

if ComparisonOp is a token or something like

%nonassoc '=' '<' '>' NOT_EQUAL GREATOR_OR_EQUAL LESS_OR_EQUAL NONASSOCIATIVE

if you have mulitple tokens and ComparisonOp is a rule that expands to any of them


As a concrete example, the following works exactly like you are requesting:

%{
#include <stdio.h>
#include <ctype.h>
int yylex();
void yyerror(const char *);
%}
%nonassoc '=' '<' '>' CMPOP
%left '+' '-' ADDOP
%left '*' '/' '%' MULOP
%token VALUE
%%
expr: expr cmp_op expr %prec CMPOP
    | expr add_op expr %prec ADDOP
    | expr mul_op expr %prec MULOP
    | VALUE
    | '(' expr ')'
    ;
cmp_op: '=' | '<' | '>' | '<' '=' | '>' '=' | '<' '>' ;
add_op: '+' | '-' ;
mul_op: '*' | '/' | '%' ;
%%
int main() { return yyparse(); }
int yylex() {
    int ch;
    while(isspace(ch = getchar()));
    if (isdigit(ch)) return VALUE;
    return ch;
}
void yyerror(const char *err) { fprintf(stderr, "%s\n", err); }

so if you are having other problems, try posting an MVCE that shows the actual problem you are having...