That conflict disappears, but another one pops up.
reduce/reduce conflict in state [stack: TModule TUnqualifiedIdentifier
TDefine TUnqualifiedIdentifier TAssignmentOperator TIf TLparen
PExpression TRparen PExp5 *] on TElse in {
[ PExpression = PExp5 * ] followed by TElse (reduce),
[ PExpressionWithElse = PExp5 * ] followed by TElse (reduce)
}
java.lang.RuntimeException:
reduce/reduce conflict in state [stack: TModule TUnqualifiedIdentifier
TDefine TUnqualifiedIdentifier TAssignmentOperator TIf TLparen
PExpression TRparen PExp5 *] on TElse in {
[ PExpression = PExp5 * ] followed by TElse (reduce),
[ PExpressionWithElse = PExp5 * ] followed by TElse (reduce)
}
at org.sablecc.sablecc.GenParser.caseStart(Unknown Source)
at org.sablecc.sablecc.node.Start.apply(Unknown Source)
at org.sablecc.sablecc.SableCC.processGrammar(Unknown Source)
at org.sablecc.sablecc.SableCC.processGrammar(Unknown Source)
at org.sablecc.sablecc.SableCC.main(Unknown Source)
My exp5 production is the equivalent of your "other". The weird thing
is that the way I've rewritten my grammar, the presence of the "else"
token should require that the parser reduce to expression_with_else.
On 03/11/2011 09:17 AM, Etienne M. Gagnon wrote:
Hi Eli,
See below.
I'm using the old SableCC 3.2, and I'm getting a weird shift-reduce
conflict for the attached grammar:
[...]
What I'm actually trying to do is just attach optional "else" clauses
to match and if expressions that adhere to the innermost expression.
I know that SableCC knows how to "intuit" that adherence, but I can't
get it to do so because it won't accept that I can have optional else
clauses at all. The error would even seem to indicate that I can
have an "else" that isn't attached to anything at all, despite the
fact that I never use the "else" token or the else_clause production
outside the context of an if or match expression.
Unfortunately, SableCC 3 does not "intuit" that else clauses belong to
the innermost construct. SableCC 3 expects an unambiguous grammar
(pure LALR(1) grammar after inlining).
In general, the following construct is ambiguous:
stmt =
{if} if exp then stmt else_clause? |
{other} other;
else_clause =
else stmt;
In order to remove the ambiguity, the grammar must be rewritten so
that an if-with-else cannot have an if-without-else as "then"
statement. Here's the general pattern:
stmt =
{if-without-else} if exp then stmt |
{if-with-else} if exp then stmt-no-if-without-else else stmt |
{other} other;
stmt-no-if-without-else =
{if-with-else} if exp then stmt-no-if-without-else else
stmt-no-if-without-else |
{other} other;
If you apply this pattern to your grammar, the conflict should disappear.
Have fun!
Etienne
Package decasyntax;
Helpers
unicode_input_character = [0..0xffff];
letter = ['A'..'Z'] | ['a'..'z'] | [0x7F .. 0xFF];
digit = ['0'..'9'];
nondigit = '_' | '?' | '!' | letter;
all = [0 .. 0xFFFF];
cr = 13;
lf = 10;
tab = 9;
eol = cr | lf | cr lf;
input_character = [unicode_input_character - [cr + lf]];
not_cr_lf = [all - [cr + lf]];
not_star = [all - '*'];
not_star_slash = [not_star - '/'];
non_zero_digit = ['1'..'9'];
hex_digit = ['0'..'9'] | ['a'..'f'] | ['A'..'F'];
octal_digit = ['0'..'7'];
zero_to_three = ['0'..'3'];
decimal_numeral = '0' | non_zero_digit digit*;
hex_numeral = '0x' hex_digit+;
octal_numeral = '0' octal_digit+;
single_character = [input_character - ['"' + '\']];
octal_escape = '\' (octal_digit octal_digit? | zero_to_three octal_digit
octal_digit);
escape_sequence = '\b' | '\t' | '\n' | '\f' | '\r' | '\"' | '\' ''' | '\\' |
octal_escape;
string_character = single_character | escape_sequence;
at_operator = '@';
exponentiation_operator = '^';
Tokens
var = 'var';
protected = 'protected';
boolean_constant = 'true' | 'false';
asterisk = '*';
division_operator = '/';
addition_operator = '+';
subtraction_operator = '-';
and_operator = 'and';
or_operator = 'or';
xor_operator = 'xor';
minus_operator = '-';
exponentiation_operator = '^';
at_operator = '@';
not_operator = 'not';
method = 'method';
override = 'override';
comma = ',';
assignment_operator = ':=';
lparen = '(';
rparen = ')';
lbracket = '{';
rbracket = '}';
lsbracket = '[';
rsbracket = ']';
dot = '.';
semicolon = ';';
colon = ':';
end = 'end';
module = 'module';
labracket = '<';
rabracket = '>';
import = 'import';
define = 'define';
new = 'new';
delete = 'delete';
extends = 'extends';
class_keyword = 'class';
variant_keyword = 'variant';
exception = 'exception';
equals = '=';
different = '<>';
greatereq = '>=';
lessereq = '<=';
function = 'function';
while = 'while';
for = 'for';
case = 'case';
if = 'if';
let = 'let';
except = 'except';
finally = 'finally';
try = 'try';
throw = 'throw';
else = 'else';
type = 'type';
underscore = '_';
type_arrow = '->';
evaluation_arrow = '=>';
region = 'region';
region_combining_operator = '++';
sizeof = 'sizeof';
match = 'match';
return = 'return';
cast = 'cast';
blank = eol | tab | ' ';
tabspace = [tab + ' '];
space = [cr + [lf + [tab + ' ']]];
comment = '/*' not_star* '*'+ (not_star_slash not_star* '*'+)* '/';
unqualified_identifier = nondigit (digit | nondigit)* | 'exception';
integer_constant = decimal_numeral | hex_numeral | octal_numeral;
string_constant = '"' string_character* '"';
Ignored Tokens
blank,
comment;
Productions
module_definition =
module [name]:unqualified_identifier [imports]:import_declaration*
[definitions]:definition* end;
qualified_identifier =
{simple} unqualified_identifier |
{imported} qualified_identifier dot unqualified_identifier;
identifier_list = {one} unqualified_identifier | {many} identifier_list comma
unqualified_identifier;
import_declaration =
import [name]:qualified_identifier;
variant_case_contents = lparen tuple_component_list rparen;
variant_component =
unqualified_identifier variant_case_contents?;
type_form =
{function} function_type_form |
{scoped_pointer} at_operator lower_type_form |
{pointer} lower_type_form asterisk |
{variant} variant_keyword lbracket variant_component+ rbracket |
{class} class_keyword function_arguments? extension_clause? lbracket
[member]:member_declaration+ destructor_definition? rbracket |
{exception} exception lparen identifier_list rparen
[extension]:extension_clause? |
{others} lower_type_form;
destructor_definition = delete [destructor]:block_expression;
function_arguments_type_form = type_form comma type_form_list;
function_type_form =
{one} [argument]:lower_type_form type_arrow [result]:lower_type_form |
{many} lparen function_arguments_type_form? rparen type_arrow
[result]:lower_type_form;
recursive_type_naming =
let [name]:unqualified_identifier equals;
tuple_component =
{type} type_form |
{binding} [name]:unqualified_identifier type_annotation;
tuple_component_list =
{one} tuple_component |
{many} tuple_component_list comma tuple_component;
tuple_form =
lsbracket tuple_component_list rsbracket;
type_parameterization = labracket [arguments]:type_form_list rabracket;
lower_type_form =
{named} [typename]:qualified_identifier type_parameterization? |
{parenthetical} recursive_type_naming? lparen type_form rparen |
{tuple} tuple_form |
{array} lower_type_form lsbracket integer_constant? rsbracket |
{region} region |
{wildcard} underscore;
definition =
{globaldef} define var? unqualified_identifier type_annotation?
assignment_operator expression |
{typedef} type unqualified_identifier [parameters]:type_form_arguments?
equals type_form |
{moduledef} module_definition |
{fundef} function_definition;
type_form_arguments =
labracket [arguments]:identifier_list rabracket;
type_form_list =
{one} type_form |
{many} type_form_list comma type_form;
type_annotation =
colon [type]:type_form;
member_declaration =
{named} protected? let_assignment_list semicolon;
extension_clause =
extends lower_type_form;
argument =
[name]:unqualified_identifier [type]:type_annotation?;
argument_list =
{one} argument |
{many} argument_list comma argument;
function_arguments = lparen [arguments]:argument_list? rparen;
function_definition =
{method} method [name]:unqualified_identifier type_form_arguments?
function_arguments [type]:type_annotation [body]:block_expression? |
{override} override [name]:qualified_identifier function_arguments
[body]:block_expression |
{function} function [name]:unqualified_identifier function_arguments
[type]:type_annotation? [body]:block_expression;
expression =
{assignmentexp} qualified_identifier assignment_operator expression |
{letexp} let lparen let_assignment_list rparen expression |
{castexp} cast labracket type_form rabracket lparen expression rparen |
{matchexp} match_expression |
{tryexp} try_expression |
{finalexp} finally [finalizer]:expression |
{forexp} for lparen [initializer]:let_assignment [first_separator]:comma
[test]:expression [second_separator]:comma [step]:expression rparen
[loop]:expression |
{whilexp} while lparen [condition]:expression rparen [body]:expression |
{throwexp} throw expression |
{ifwithoutelseexp} if lparen [condition]:expression rparen
[thenbody]:expression |
{ifwithelseexp} if lparen [condition]:expression rparen
[thenbody]:expression_with_else else_clause |
{blockexp} block_expression |
{regionexp} region lsbracket integer_constant rsbracket |
{returnexp} return expression |
{others} exp5;
expression_with_else =
{assignmentexp} qualified_identifier assignment_operator expression |
{letexp} let lparen let_assignment_list rparen expression |
{castexp} cast labracket type_form rabracket lparen expression rparen |
{matchexp} match_with_else |
{tryexp} try_expression |
{finalexp} finally [finalizer]:expression |
{forexp} for lparen [initializer]:let_assignment [first_separator]:comma
[test]:expression [second_separator]:comma [step]:expression rparen
[loop]:expression |
{whilexp} while lparen [condition]:expression rparen [body]:expression |
{throwexp} throw expression |
{ifwithelseexp} if lparen [condition]:expression rparen
[thenbody]:expression_with_else else [elsebody]:expression_with_else |
{blockexp} block_expression |
{regionexp} region lsbracket integer_constant rsbracket |
{returnexp} return expression |
{others} exp5;
//Increasing precedence levels.
exp1 =
{at} at_operator [variable]:qualified_identifier |
{sizeof} sizeof lparen type_form rparen |
{primitive_integer} integer_constant |
{primitive_boolean} boolean_constant |
{primitive_string} string_constant |
{tuple} lsbracket expression_list rsbracket |
{lambda} function function_arguments block_expression |
{call} function_call_expression |
{parenthetical} parenthetical_expression |
{identifier} qualified_identifier;
exp2 =
{exponentiation} [exp1]:exp1 exponentiation_operator [exp2]:exp2 |
{minus} minus_operator exp2 |
{not} not_operator exp2 |
{others} exp1;
exp3 =
{and} [exp1]:exp3 and_operator [exp2]:exp2 |
{or} [exp1]:exp3 or_operator [exp2]:exp2 |
{xor} [exp1]:exp3 xor_operator [exp2]:exp2 |
{multiply} [exp1]:exp3 asterisk [exp2]:exp2 |
{division} [exp1]:exp3 division_operator [exp2]:exp2 |
{others} exp2;
exp4 =
{plus} [exp1]:exp4 addition_operator [exp2]:exp3 |
{minus} [exp1]:exp4 subtraction_operator [exp2]:exp3 |
{regions} [exp1]:exp4 region_combining_operator [exp2]:exp3 |
{others} exp3;
exp5 =
{greater} [exp1]:exp4 rabracket [exp2]:exp4 |
{greatereq} [exp1]:exp4 greatereq [exp2]:exp4 |
{less} [exp1]:exp4 labracket [exp2]:exp4 |
{lessereq} [exp1]:exp4 lessereq [exp2]:exp4 |
{equals} [exp1]:exp4 equals [exp2]:exp4 |
{different} [exp1]:exp4 different [exp2]:exp4 |
{others} exp4;
function_call_expression =
{variable} [function]:qualified_identifier lparen
[arguments]:expression_list? rparen |
{parens} [function]:parenthetical_expression lparen
[arguments]:expression_list? rparen |
{region_alloc} new [region]:parenthetical_expression
[argument]:parenthetical_expression |
{region_free} delete [argument]:parenthetical_expression |
{deleteregion} delete region [which]:parenthetical_expression;
except_case_clause =
case [name]:unqualified_identifier type_annotation evaluation_arrow
[body]:expression;
try_expression =
{one} try expression except except_case_clause |
{many} try expression except lbracket except_case_clause+ rbracket;
parenthetical_expression =
lparen expression rparen;
expression_list =
{one} expression |
{many} expression_list comma expression;
else_clause =
else [else_body]:expression;
let_assignment =
unqualified_identifier type_annotation? assignment_operator expression;
let_assignment_list =
{one} let_assignment |
{many} let_assignment_list comma let_assignment;
match_case_clause =
{variable} case [name]:unqualified_identifier type_annotation
evaluation_arrow [body]:expression |
{variant} case qualified_identifier variant_case_contents? evaluation_arrow
[body]:expression |
{tuple} case tuple_form evaluation_arrow [body]:expression;
match_expression =
{one} match lparen expression rparen match_case_clause else_clause? |
{many} match lparen expression rparen lbracket match_case_clause+ rbracket
else_clause?;
match_with_else =
{one} match lparen expression rparen match_case_clause else
expression_with_else |
{many} match lparen expression rparen lbracket match_case_clause+ rbracket
else expression_with_else;
block_contents =
{one} expression |
{many} block_contents [separator]:semicolon expression
[terminator]:semicolon;
block_expression =
lbracket block_contents rbracket;
_______________________________________________
SableCC-Discussion mailing list
[email protected]
http://lists.sablecc.org/listinfo/sablecc-discussion