anchor.diff:               isLBracket(prevToken) || isRBracket(nextToken));
   }
   
  +private boolean isPrevTokenElementSeparator() {
  +    switch(input.LA(-1)) {
  +    case COMMA:
  +    case OTHER_WHITESPACE:
  +        return true;
  +    default:
  +        return false;
  +    }
  +}
  +
   private final java.util.Stack<Integer> bracketStack = new java.util.Stack<Integer>();
   private boolean inParens() { return bracketStack.peek() == LPAREN; }
   }
  
positive.code:      IDENTIFIER
    ;
  
  lparen :
       LPAREN { bracketStack.push(LPAREN); }
    ;
  
  rparen :
       RPAREN { bracketStack.pop(); }
    ;
  
  lsquare :
       LSQUARE { bracketStack.push(LSQUARE); }
    ;
  
  rsquare :
       RSQUARE { bracketStack.pop(); }
    ;
  
  lcurly :
       LCURLY { bracketStack.push(LCURLY); }
    ;
  
  rcurly :
       RCURLY { bracketStack.pop(); }
    ;
  
  //NB: not distinguishing between identifiers and keywords at this level - everything is an ID
  //NB: not distinguishing between decimal and hex numbers at this level
  
negative.code:   ;
  
  element_separator :
       {isPrevTokenElementSeparator()}? COMMA -> template() "" //delete comma
    |  COMMA                                                   //just echo
    |  {isElementSeparator()}?
          ( {isPrevTokenElementSeparator()}? FILLER            //just echo
          | FILLER -> template(filler={$text}) ",<filler>")    //insert comma
    ;
  
  input_params :
  