Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More fine grain control of precedences #705

Open
theKidOfArcrania opened this issue Feb 5, 2023 · 0 comments
Open

More fine grain control of precedences #705

theKidOfArcrania opened this issue Feb 5, 2023 · 0 comments

Comments

@theKidOfArcrania
Copy link

theKidOfArcrania commented Feb 5, 2023

Hi I'm having trouble trying to disambiguate this fairly simple grammar (note that this is only a small chunk of a larger language):

grammar;

pub ETop = <E>;

E: String = {
  #[precedence(level="0")]
  var => <>,
  "let" <v: var> "=" <e1: ETop> "in" <e2: ETop> =>
    format!("(let var = {e1} in {e2})"),

  #[precedence(level="1")] #[assoc(side="left")]
  <e1:E> ";" <e2: E> => format!("({e1} ; {e2})"),
}

var: String = {
  r"[A-Za-z]" => <>.into(),
}

This would result as the following shift-reduce conflict:

    The following symbols can be reduced in two ways:
      "let" var "=" ETop "in" E ";" E0

    They could be reduced like so:
      "let" var "=" ETop "in" E      ╷ ";" E0
      │                       └─ETop─┤      │
      ├─E0───────────────────────────┤      │
      ├─E────────────────────────────┘      │
      └─E───────────────────────────────────┘

    Alternatively, they could be reduced like so:
      "let" var "=" ETop "in" E ";" E0
      │                       ├─E────┤
      │                       └─ETop─┤
      └─E0───────────────────────────┘

However we also can't place the let ... in ... production rule as a lower precedence to everything else because then we wouldn't be able to parse inputs such as b; let a = b in c. In essence, we want to have let be part of a set of high precedence keywords, but also let the trailing expression have low precedence when reducing.

The solution (using conditional macros/explicitly handling no-short-if case) in #386 does not work as both solutions (the linked example code) nor the linked java grammar has the issue where we have a keyword "let" with a high priority yet have the trailing expression as low priority (i.e. a mixed context-dependent precedence) (note ternary in java tactfully does not have an "if" to denote the beginning of a ternary expression, so it can just be placed as a low priority operator).

A solution in yacc has been to mark the let keyword as high precedence, but mark the whole production as a low precedence, ex:


%token LET IN
%token<str> VAR

%nonassoc P_LET
%left ';'
%nonassoc LET

%%

expr: VAR { }
    | LET VAR '=' expr IN expr %prec P_LET { }
    | expr ';' expr { }
    ;

In essence, we are saying to prefer shift over reduce if we are in the let ... in ... production. This seems to be similar to issue #620 but more generalized.

Note this was also briefly mentioned in #67, though was never actually addressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant