I'm trying to implement a toy language with grammar inspired by Scala. I used part of the Scala Syntax Specification:
Expr1 : ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr]
      | ...
In this toy language, everything is an expression (if-else, for, while has a return value), and seperated by ; or \n.
Here's the parser.y:
%code top {
#include <cstdio>
}
%union {
    int n;
    Ast *ast;
}
%code requires {
class Ast;
int yylex(void);
void yyerror(const char *msg);
}
%token<n> NUM 
%token<n> PLUS '+'
%token<n> MINUS '-'
%token<n> TIMES '*'
%token<n> DIVIDE '/'
%token<n> SEMICOLON ';'
%token<n> NEWLINE '\n'
%token<n> IF "if"
%token<n> ELSE "else"
%token<n> LPAREN '('
%token<n> RPAREN ')'
%type<ast> prog expr primaryExpr optionalElse semi optionalSemi optionalNewlines newlines
%left PLUS MINUS
%left TIMES DIVIDE
%start prog
%%
prog : expr
     ;
expr : "if" '(' primaryExpr ')' optionalNewlines expr optionalElse { $$ = nullptr; }
     | primaryExpr
     ;
optionalElse : optionalSemi "else" expr { $$ = nullptr; }
             | %empty { $$ = nullptr; }
             ;
primaryExpr : NUM { $$ = nullptr; }
            | primaryExpr '+' NUM { $$ = nullptr; }
            | primaryExpr '-' NUM { $$ = nullptr; }
            | primaryExpr '*' NUM { $$ = nullptr; }
            | primaryExpr '/' NUM { $$ = nullptr; }
            ;
semi : ';' { $$ = nullptr; }
     | '\n' { $$ = nullptr; }
     ;
optionalSemi : semi { $$ = nullptr; }
             | %empty { $$ = nullptr; }
             ;
optionalNewlines : newlines { $$ = nullptr; }
                 | %empty { $$ = nullptr; }
                 ;
newlines : '\n' { $$ = nullptr; }
         | newlines '\n' { $$ = nullptr; }
         ;
%%
void yyerror(const char *msg) {
    fprintf(stderr, "%s\n", msg);
}
This is my grammar compiled with: bison --debug --verbose -Wcounterexamples -o grammar.tab.cpp --defines=grammar.tab.h grammar.y
It gives me output:
Terminals unused in grammar
    PLUS
    MINUS
    TIMES
    DIVIDE
    SEMICOLON
    NEWLINE
    LPAREN
    RPAREN
Rules useless in parser due to conflicts
   14 optionalSemi: %empty
State 21 conflicts: 2 shift/reduce, 1 reduce/reduce
Grammar
    0 $accept: prog $end
    1 prog: expr
    2 expr: "if" '(' primaryExpr ')' optionalNewlines expr optionalElse
    3     | primaryExpr
    4 optionalElse: optionalSemi "else" expr
    5             | %empty
    6 primaryExpr: NUM
    7            | primaryExpr '+' NUM
    8            | primaryExpr '-' NUM
    9            | primaryExpr '*' NUM
   10            | primaryExpr '/' NUM
   11 semi: ';'
   12     | '\n'
   13 optionalSemi: semi
   14             | %empty
   15 optionalNewlines: newlines
   16                 | %empty
   17 newlines: '\n'
   18         | newlines '\n'
Terminals, with rules where they appear
    $end (0) 0
    '\n' <n> (10) 12 17 18
    '(' <n> (40) 2
    ')' <n> (41) 2
    '*' <n> (42) 9
    '+' <n> (43) 7
    '-' <n> (45) 8
    '/' <n> (47) 10
    ';' <n> (59) 11
    error (256)
    NUM <n> (258) 6 7 8 9 10
    PLUS <n> (259)
    MINUS <n> (260)
    TIMES <n> (261)
    DIVIDE <n> (262)
    SEMICOLON <n> (263)
    NEWLINE <n> (264)
    "if" <n> (265) 2
    "else" <n> (266) 4
    LPAREN <n> (267)
    RPAREN <n> (268)
Nonterminals, with rules where they appear
    $accept (22)
        on left: 0
    prog <ast> (23)
        on left: 1
        on right: 0
    expr <ast> (24)
        on left: 2 3
        on right: 1 2 4
    optionalElse <ast> (25)
        on left: 4 5
        on right: 2
    primaryExpr <ast> (26)
        on left: 6 7 8 9 10
        on right: 2 3 7 8 9 10
    semi <ast> (27)
        on left: 11 12
        on right: 13
    optionalSemi <ast> (28)
        on left: 13 14
        on right: 4
    optionalNewlines <ast> (29)
        on left: 15 16
        on right: 2
    newlines <ast> (30)
        on left: 17 18
        on right: 15 18
State 0
    0 $accept: • prog $end
    NUM   shift, and go to state 1
    "if"  shift, and go to state 2
    prog         go to state 3
    expr         go to state 4
    primaryExpr  go to state 5
State 1
    6 primaryExpr: NUM •
    $default  reduce using rule 6 (primaryExpr)
State 2
    2 expr: "if" • '(' primaryExpr ')' optionalNewlines expr optionalElse
    '('  shift, and go to state 6
State 3
    0 $accept: prog • $end
    $end  shift, and go to state 7
State 4
    1 prog: expr •
    $default  reduce using rule 1 (prog)
State 5
    3 expr: primaryExpr •
    7 primaryExpr: primaryExpr • '+' NUM
    8            | primaryExpr • '-' NUM
    9            | primaryExpr • '*' NUM
   10            | primaryExpr • '/' NUM
    '+'  shift, and go to state 8
    '-'  shift, and go to state 9
    '*'  shift, and go to state 10
    '/'  shift, and go to state 11
    $default  reduce using rule 3 (expr)
State 6
    2 expr: "if" '(' • primaryExpr ')' optionalNewlines expr optionalElse
    NUM  shift, and go to state 1
    primaryExpr  go to state 12
State 7
    0 $accept: prog $end •
    $default  accept
State 8
    7 primaryExpr: primaryExpr '+' • NUM
    NUM  shift, and go to state 13
State 9
    8 primaryExpr: primaryExpr '-' • NUM
    NUM  shift, and go to state 14
State 10
    9 primaryExpr: primaryExpr '*' • NUM
    NUM  shift, and go to state 15
State 11
   10 primaryExpr: primaryExpr '/' • NUM
    NUM  shift, and go to state 16
State 12
    2 expr: "if" '(' primaryExpr • ')' optionalNewlines expr optionalElse
    7 primaryExpr: primaryExpr • '+' NUM
    8            | primaryExpr • '-' NUM
    9            | primaryExpr • '*' NUM
   10            | primaryExpr • '/' NUM
    '+'  shift, and go to state 8
    '-'  shift, and go to state 9
    '*'  shift, and go to state 10
    '/'  shift, and go to state 11
    ')'  shift, and go to state 17
State 13
    7 primaryExpr: primaryExpr '+' NUM •
    $default  reduce using rule 7 (primaryExpr)
State 14
    8 primaryExpr: primaryExpr '-' NUM •
    $default  reduce using rule 8 (primaryExpr)
State 15
    9 primaryExpr: primaryExpr '*' NUM •
    $default  reduce using rule 9 (primaryExpr)
State 16
   10 primaryExpr: primaryExpr '/' NUM •
    $default  reduce using rule 10 (primaryExpr)
State 17
    2 expr: "if" '(' primaryExpr ')' • optionalNewlines expr optionalElse
    '\n'  shift, and go to state 18
    $default  reduce using rule 16 (optionalNewlines)
    optionalNewlines  go to state 19
    newlines          go to state 20
State 18
   17 newlines: '\n' •
    $default  reduce using rule 17 (newlines)
State 19
    2 expr: "if" '(' primaryExpr ')' optionalNewlines • expr optionalElse
    NUM   shift, and go to state 1
    "if"  shift, and go to state 2
    expr         go to state 21
    primaryExpr  go to state 5
State 20
   15 optionalNewlines: newlines •
   18 newlines: newlines • '\n'
    '\n'  shift, and go to state 22
    $default  reduce using rule 15 (optionalNewlines)
State 21
    2 expr: "if" '(' primaryExpr ')' optionalNewlines expr • optionalElse
    ';'   shift, and go to state 23
    '\n'  shift, and go to state 24
    ';'       [reduce using rule 5 (optionalElse)]
    '\n'      [reduce using rule 5 (optionalElse)]
    "else"    reduce using rule 5 (optionalElse)
    "else"    [reduce using rule 14 (optionalSemi)]
    $default  reduce using rule 5 (optionalElse)
    optionalElse  go to state 25
    semi          go to state 26
    optionalSemi  go to state 27
    shift/reduce conflict on token ';':
        5 optionalElse: • %empty
       11 semi: • ';'
      Example: "if" '(' primaryExpr ')' optionalNewlines "if" '(' primaryExpr ')' optionalNewlines expr • ';' "else" expr
      Shift derivation
        expr
        ↳ "if" '(' primaryExpr ')' optionalNewlines expr                                                                        optionalElse
                                                    ↳ "if" '(' primaryExpr ')' optionalNewlines expr optionalElse               ↳ ε
                                                                                                     ↳ optionalSemi "else" expr
                                                                                                       ↳ semi
                                                                                                         ↳ • ';'
      Reduce derivation
        expr
        ↳ "if" '(' primaryExpr ')' optionalNewlines expr                                                          optionalElse
                                                    ↳ "if" '(' primaryExpr ')' optionalNewlines expr optionalElse ↳ optionalSemi "else" expr
                                                                                                     ↳ •            ↳ semi
                                                                                                                      ↳ ';'
    shift/reduce conflict on token '\n':
        5 optionalElse: • %empty
       12 semi: • '\n'
      Example: "if" '(' primaryExpr ')' optionalNewlines "if" '(' primaryExpr ')' optionalNewlines expr • '\n' "else" expr
      Shift derivation
        expr
        ↳ "if" '(' primaryExpr ')' optionalNewlines expr                                                                        optionalElse
                                                    ↳ "if" '(' primaryExpr ')' optionalNewlines expr optionalElse               ↳ ε
                                                                                                     ↳ optionalSemi "else" expr
                                                                                                       ↳ semi
                                                                                                         ↳ • '\n'
      Reduce derivation
        expr
        ↳ "if" '(' primaryExpr ')' optionalNewlines expr                                                          optionalElse
                                                    ↳ "if" '(' primaryExpr ')' optionalNewlines expr optionalElse ↳ optionalSemi "else" expr
                                                                                                     ↳ •            ↳ semi
                                                                                                                      ↳ '\n'
    reduce/reduce conflict on token "else":
        5 optionalElse: • %empty
       14 optionalSemi: • %empty
      Example: •
      First reduce derivation
        optionalElse
        ↳ •
      Second reduce derivation
        optionalSemi
        ↳ •
State 22
   18 newlines: newlines '\n' •
    $default  reduce using rule 18 (newlines)
State 23
   11 semi: ';' •
    $default  reduce using rule 11 (semi)
State 24
   12 semi: '\n' •
    $default  reduce using rule 12 (semi)
State 25
    2 expr: "if" '(' primaryExpr ')' optionalNewlines expr optionalElse •
    $default  reduce using rule 2 (expr)
State 26
   13 optionalSemi: semi •
    $default  reduce using rule 13 (optionalSemi)
State 27
    4 optionalElse: optionalSemi • "else" expr
    "else"  shift, and go to state 28
State 28
    4 optionalElse: optionalSemi "else" • expr
    NUM   shift, and go to state 1
    "if"  shift, and go to state 2
    expr         go to state 29
    primaryExpr  go to state 5
State 29
    4 optionalElse: optionalSemi "else" expr •
    $default  reduce using rule 4 (optionalElse)
How should I fix the State 21 conflicts: 2 shift/reduce, 1 reduce/reduce?