简体   繁体   中英

Fixing Ambiguous Grammer in CUP

I am having problems with a grammer I am using to make a CUP Parser. The grammer is as follows: In CUP format.

terminal           PLUS, MINUS, TIMES, DIV, EQUALS, LESS, IF, THEN, ELSE, LET, EQ, IN, FUN
                    , ARROW, LPAREN, RPAREN, INVALID_TOKEN, APPL;
terminal String   NUMBER, ID;
   
// Non terminals used in the grammar section.
//non terminal exprList;
non terminal Expr expr, cExpr;

precedence left LPAREN, RPAREN;
precedence left  PLUS, MINUS;
precedence left TIMES, DIV;
precedence left LESS;
precedence left EQUALS;
precedence right EQ;
precedence right ARROW;

start with cExpr;
/* ----------------------------Grammar Section-------------------- */
// to do: implement function application

cExpr ::=
    IF cExpr:ifExp THEN cExpr:thenExp ELSE cExpr:elseExp
        {: RESULT = new ExprIfThenElse(ifExp, thenExp, elseExp); :}
    | LET ID:id EQ cExpr:value IN cExpr:expression
        {: RESULT = new ExprLetIn(id, value, expression); :}
    | FUN ID:id ARROW cExpr:e
        {: RESULT = new ExprLambda(id, e); :}
    | rExpr:e
        {:RESULT = e;:}
;

expr ::=
    expr:l PLUS expr:r
        {: RESULT = new ExprBinary(l, r, Operator.Plus); :}
    | expr:l TIMES expr:r
        {: RESULT = new ExprBinary(l, r, Operator.Times); :}
    | expr:l DIV expr:r
        {: RESULT = new ExprBinary(l, r, Operator.Div); :}
    | expr:l MINUS expr:r
        {: RESULT = new ExprBinary(l, r, Operator.Minus); :}
    | expr:l LESS expr:r
        {: RESULT = new ExprBinary(l, r, Operator.Less); :}
    | expr:l EQUALS expr:r
        {: RESULT = new ExprBinary(l, r, Operator.Equals); :}
    |expr:exprFunc expr:arg
        {: RESULT = new ExprFuncApp(exprFunc, arg); :}
    | NUMBER:n
        {: RESULT = new ExprNumber(n); :}
    | ID:i
        {: RESULT = new ExprId(i); :}
    | LPAREN cExpr:e RPAREN
         {: RESULT = e; :}
;

Or written out:


CExp -> if CExp then CExp else CExp 
      | let if = CExp in CExp 
      | fun id -> CExp 
      | Exp 
Exp  -> Exp op Exp 
      | Exp Exp 
      | {identifier} 
      | {integer literal} 
      | ( CExp ) 
op   -> + | - | * | / | < | ==

My main problem resides with the function operator Exp Exp. "f 4" would mean something like function f with value 4 as argument. But as this grammer is obviously ambiguous (for example for the input "5 * f 1") i tried to make it unambiguous.

I tried to make it unambiguous was making a step inbetween with the Exp Exp operator:

terminal           PLUS, MINUS, TIMES, DIV, EQUALS, LESS, IF, THEN, ELSE, LET, EQ, IN, FUN
                    , ARROW, LPAREN, RPAREN, INVALID_TOKEN, APPL;
terminal String   NUMBER, ID;
   
// Non terminals used in the grammar section.
//non terminal exprList;
non terminal Expr expr, cExpr,rExpr;


precedence left LPAREN, RPAREN;
precedence left  PLUS, MINUS;
precedence left TIMES, DIV;
precedence left LESS;
precedence left EQUALS;
precedence right EQ;
precedence right ARROW;
precedence left APPL;

start with cExpr;
/* ----------------------------Grammar Section-------------------- */
// to do: implement function application

cExpr ::=
    IF cExpr:ifExp THEN cExpr:thenExp ELSE cExpr:elseExp
        {: RESULT = new ExprIfThenElse(ifExp, thenExp, elseExp); :}
    | LET ID:id EQ cExpr:value IN cExpr:expression
        {: RESULT = new ExprLetIn(id, value, expression); :}
    | FUN ID:id ARROW cExpr:e
        {: RESULT = new ExprLambda(id, e); :}
    | rExpr:e
        {:RESULT = e;:}
;

expr ::=
    expr:l PLUS rExpr:r
        {: RESULT = new ExprBinary(l, r, Operator.Plus); :}
    | expr:l TIMES rExpr:r
        {: RESULT = new ExprBinary(l, r, Operator.Times); :}
    | expr:l DIV rExpr:r
        {: RESULT = new ExprBinary(l, r, Operator.Div); :}
    | expr:l MINUS rExpr:r
        {: RESULT = new ExprBinary(l, r, Operator.Minus); :}
    | expr:l LESS rExpr:r
        {: RESULT = new ExprBinary(l, r, Operator.Less); :}
    | expr:l EQUALS rExpr:r
        {: RESULT = new ExprBinary(l, r, Operator.Equals); :}
    | NUMBER:n
        {: RESULT = new ExprNumber(n); :}
    | ID:i
        {: RESULT = new ExprId(i); :}
    | LPAREN cExpr:e RPAREN
         {: RESULT = e; :}
;
rExpr ::=
    expr:e
        {:RESULT = e;:}
    |rExpr:exprFunc expr:arg
        {: RESULT = new ExprFuncApp(exprFunc, arg); :} %prec APPL
;

This way i hoped it would make it unambigous, which is not the case...
I tried my hand on trying with precedence rules of CUP but I also did not get anywhere with that.\ It is a LR(0) Parser, so i also couldn't use look aheads. If someone could give me a tip on how to make this grammer unambiguous i would appreciate it.

This is the solution i came up with, I hope someone benefits from it. It is pretty simple and i only needed to account for associativity and change the grammer to make it unambiguous, instead of relying on precedence rules.

    /* ------------Declaration of Terminals and Non Terminals Section----------- */
   
//Terminals (tokens returned by the scanner).  
terminal           PLUS, MINUS, TIMES, DIV, EQUALS, LESS, IF, THEN, ELSE, LET, EQ, IN, FUN
                    , ARROW, LPAREN, RPAREN, INVALID_TOKEN, APPL;
terminal String   NUMBER, ID;
   
// Non terminals used in the grammar section.
//non terminal exprList;
non terminal Expr expr, cExpr, ter, plusExpr, multExpr, lessExpr, eqExpr , funcExpr;

precedence right EQ;
precedence right ARROW;

start with cExpr;
/* ----------------------------Grammar Section-------------------- */

cExpr ::=
    IF cExpr:ifExp THEN cExpr:thenExp ELSE cExpr:elseExp
        {: RESULT = new ExprIfThenElse(ifExp, thenExp, elseExp); :}
    | LET ID:id EQ cExpr:value IN cExpr:expression
        {: RESULT = new ExprLetIn(new ExprId(id), value, expression); :}
    | FUN ID:id ARROW cExpr:e
        {: RESULT = new ExprLambda(new ExprId(id), e); :}
    | plusExpr:e
        {:RESULT = e;:}
;
plusExpr ::=
    plusExpr:l PLUS multExpr:r
            {: RESULT = new ExprBinary(l, r, Operator.Plus); :}
    | plusExpr:l MINUS multExpr:r
            {: RESULT = new ExprBinary(l, r, Operator.Minus); :}
    | multExpr:t
            {: RESULT = t;:}
;

multExpr ::=
    multExpr:l TIMES lessExpr:r
            {: RESULT = new ExprBinary(l, r, Operator.Times); :}
    | multExpr:l DIV lessExpr:r
            {: RESULT = new ExprBinary(l, r, Operator.Div); :}
    | lessExpr:s
            {: RESULT = s;:}
;

lessExpr ::=
    lessExpr:l LESS eqExpr:r
            {: RESULT = new ExprBinary(l, r, Operator.Less); :}
    | eqExpr:u
            {: RESULT = u;:}
;

eqExpr ::=
    | eqExpr:l EQUALS funcExpr:r
            {: RESULT = new ExprBinary(l, r, Operator.Equals); :}
    | funcExpr:w
        {: RESULT = w;:}
;

funcExpr ::=
    funcExpr:exprFunc expr:arg
            {: RESULT = new ExprFuncApp(exprFunc, arg); :}
    | expr:e
        {:RESULT = e;:}
;

expr ::=
    ter:t
        {: RESULT = t ;:}
    | LPAREN cExpr:e RPAREN
         {: RESULT = e; :}
;

ter ::=
    NUMBER:n
        {: RESULT = new ExprNumber(n); :}
    | ID:i
        {: RESULT = new ExprId(i); :}
;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM