I have the following start of a Pascal grammar The grammar works correctly. What I don't understand is I have a very similar grammar in my 6502 assembler that does not have any reduce/shift conflicts.
%no-lines
%{
// ***********************************************************************
// Author : Paul Baxter
// ***********************************************************************
#pragma warning(disable:4065)
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdbool.h>
#include "node.h"
#include "pascal.h"
#include "expander.h"
#include "pascal.tab.h"
%}
%union
{
char cValue; /* char value */
int iValue; /* integer value */
bool bValue; /* bool value */
double dValue; /* double value */
struct PString *pValue; /* pascal string value */
struct parse_node *nPtr; /* node pointer */
};
%token <iValue> INTEGER /* integer */
%token <dValue> REAL /* real */
%token <pValue> ST /* string */
%token <bValue> BO /* bool */
%token <pValue> SYM /* symbol */
%token <iValue> VARTYPE /* variable type */
%token <cValue> CH /* char */
%token PROGRAM INPUT OUTPUT BEG END ENDP SC PARAMLIST NOT PROC STATEMENT VAR CONST CO DECL AS
%nonassoc ELSE '~'
%left SHIFT_LEFT SHIFT_RIGHT UMINUS UPLUS
%left OR AND GE LE EQ NE '>' '<'
%left BIT_OR BIT_AND '^'
%left '+' '-'
%left '*' '/'
%type <nPtr> header stmt begstmt endstmt endprogram subexpr expr assign opr
%type <nPtr> parameter_list procedure_call var_decl varstmt sym_list conststmt basetype
%type <nPtr> const_decl
%%
program
: program stmt { Ex($2); }
| { }
;
stmt
: header { $$ = Statement(1, $1); }
| procedure_call { $$ = Statement(1, $1); }
| conststmt { $$ = Statement(1, $1); }
| const_decl { $$ = Statement(1, $1); }
| var_decl { $$ = Statement(1, $1); }
| varstmt { $$ = Statement(1, $1); }
| begstmt { $$ = Statement(1, $1); }
| endstmt { $$ = Statement(1, $1); }
| assign { $$ = Statement(1, $1); }
| endprogram { $$ = Statement(1, $1); }
;
begstmt
: BEG { $$ = Beg(); }
;
endstmt
: END { $$ = End(); }
;
header
: PROGRAM SYM '(' INPUT ')' SC { $$ = ProgHeader($2, true, false); }
| PROGRAM SYM '(' OUTPUT ')' SC { $$ = ProgHeader($2, false, true); }
| PROGRAM SYM '(' INPUT ',' OUTPUT ')' SC { $$ = ProgHeader($2, true, true); }
| PROGRAM SYM '(' ')' SC { $$ = ProgHeader($2, false, false); }
| PROGRAM SYM SC { $$ = ProgHeader($2, false, false); }
;
endprogram
: ENDP { $$ = EndProg(); }
;
varstmt
: VAR { $$ = Var(); }
;
conststmt
: CONST { $$ = Const(); }
;
expr
: basetype { $$ = $1; }
| opr { $$ = $1; }
;
basetype
: INTEGER { $$ = IntCon($1); }
| REAL { $$ = RealCon($1); }
| CH { $$ = CharCon($1); }
| ST { $$ = StrListNode(1, $1); }
| SYM { $$ = SymVal($1); }
;
opr
: '-' subexpr %prec UMINUS { $$ = Oper(UMINUS, 1, $2); }
| '+' subexpr %prec UPLUS { $$ = Oper(UPLUS, 1, $2); }
| NOT subexpr { $$ = Oper(NOT, 1, $2); }
| subexpr OR subexpr { $$ = Oper(OR, 2, $1, $3); }
| subexpr AND subexpr { $$ = Oper(AND, 2, $1, $3); }
| subexpr SHIFT_LEFT subexpr { $$ = Oper(SHIFT_LEFT, 2, $1, $3); }
| subexpr SHIFT_RIGHT subexpr { $$ = Oper(SHIFT_RIGHT, 2, $1, $3); }
| subexpr GE subexpr { $$ = Oper(GE, 2, $1, $3); }
| subexpr LE subexpr { $$ = Oper(LE, 2, $1, $3); }
| subexpr NE subexpr { $$ = Oper(NE, 2, $1, $3); }
| subexpr BIT_AND subexpr { $$ = Oper(BIT_AND, 2, $1, $3); }
| subexpr BIT_OR subexpr { $$ = Oper(BIT_OR, 2, $1, $3); }
| subexpr '^' subexpr { $$ = Oper('^', 2, $1, $3); }
| subexpr '+' subexpr { $$ = Oper('+', 2, $1, $3); }
| subexpr '-' subexpr { $$ = Oper('-', 2, $1, $3); }
| subexpr '*' subexpr { $$ = Oper('*', 2, $1, $3); }
| subexpr '/' subexpr { $$ = Oper('/', 2, $1, $3); }
;
subexpr
: expr { $$ = $1; }
| '(' subexpr ')' { $$ = $2; }
;
assign
: SYM AS expr SC { $$ = Oper(AS, 2, Id($1), $3); }
;
procedure_call
: SYM '(' parameter_list ')' SC { $$ = ProcCall($1, ParamListHead); }
| SYM '(' ')' SC { $$ = ProcCall($1, NULL); }
| SYM SC { $$ = ProcCall($1, NULL); }
;
parameter_list
: expr { $$ = ParamList(Param($1)); }
| parameter_list ',' expr { $$ = ParamList(Param($3)); }
;
const_decl
: SYM '=' expr SC { $$ = ConDecl(Id($1), $3); }
;
var_decl
: sym_list CO VARTYPE SC { $$ = VarDecl($1, IntCon($3)); }
;
sym_list
: SYM { $$ = SymList(Id($1)); }
| sym_list ',' SYM { $$ = SymList(Id($3)); }
;
%%
This produces 14 shift/reduce conflicts that I don't understand.
State 51 conflicts: 14 shift/reduce
State 51
32 opr: NOT subexpr .
33 | subexpr . OR subexpr
34 | subexpr . AND subexpr
35 | subexpr . SHIFT_LEFT subexpr
36 | subexpr . SHIFT_RIGHT subexpr
37 | subexpr . GE subexpr
38 | subexpr . LE subexpr
39 | subexpr . NE subexpr
40 | subexpr . BIT_AND subexpr
41 | subexpr . BIT_OR subexpr
42 | subexpr . '^' subexpr
43 | subexpr . '+' subexpr
44 | subexpr . '-' subexpr
45 | subexpr . '*' subexpr
46 | subexpr . '/' subexpr
SHIFT_RIGHT shift, and go to state 56
SHIFT_LEFT shift, and go to state 57
NE shift, and go to state 58
LE shift, and go to state 59
GE shift, and go to state 60
AND shift, and go to state 61
OR shift, and go to state 62
'^' shift, and go to state 63
BIT_AND shift, and go to state 64
BIT_OR shift, and go to state 65
'+' shift, and go to state 66
'-' shift, and go to state 67
'*' shift, and go to state 68
'/' shift, and go to state 69
SHIFT_RIGHT [reduce using rule 32 (opr)]
SHIFT_LEFT [reduce using rule 32 (opr)]
NE [reduce using rule 32 (opr)]
LE [reduce using rule 32 (opr)]
GE [reduce using rule 32 (opr)]
AND [reduce using rule 32 (opr)]
OR [reduce using rule 32 (opr)]
'^' [reduce using rule 32 (opr)]
BIT_AND [reduce using rule 32 (opr)]
BIT_OR [reduce using rule 32 (opr)]
'+' [reduce using rule 32 (opr)]
'-' [reduce using rule 32 (opr)]
'*' [reduce using rule 32 (opr)]
'/' [reduce using rule 32 (opr)]
$default reduce using rule 32 (opr)
it is the opr subexpr . subexpr The grammar works but I would rather not have any conflicts. I want to understand why it is a conflict and how to fix it.
Thanks in advance