I'm using the old SableCC 3.2, and I'm getting a weird shift-reduce conflict for the attached grammar:

shift/reduce conflict in state [stack: TModule TUnqualifiedIdentifier TDefine TUnqualifiedIdentifier TAssignmentOperator TMatch PExpression PMatchCaseClause *] on TElse in {
    [ PElseClause = * TElse PExpression ] (shift),
[ PExpression = TMatch PExpression PMatchCaseClause * ] followed by TElse (reduce)
}
java.lang.RuntimeException:

shift/reduce conflict in state [stack: TModule TUnqualifiedIdentifier TDefine TUnqualifiedIdentifier TAssignmentOperator TMatch PExpression PMatchCaseClause *] on TElse in {
    [ PElseClause = * TElse PExpression ] (shift),
[ PExpression = TMatch PExpression PMatchCaseClause * ] 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)
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.

Any ideas?
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 |
    {condexp} if_expression |
    {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;
    
  if_expression =
    {then} if lparen [condition]:expression rparen [then_body]:expression 
else_clause?;
    
  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 expression match_case_clause else_clause? |
    {many} match expression lbracket match_case_clause+ rbracket else_clause?;
    
  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

Reply via email to