anchor.diff:              | "FEATURE"i
               | "FONTSET"i
               | "GRID"i
  -            | "INCLUDE"i
               | "JOIN"i
               | "LABEL"i
               | "LAYER"i
  
positive.code: %import common.FLOAT
  %import common.INT
  
  STRING1: /".*?(?<!\\\\)(\\\\\\\\)*?"i?/
  STRING2: /'.*?(?<!\\\\)(\\\\\\\\)*?'i?/
  STRING3: /`.*?`i?/   // XXX TODO
  REGEXP1.2: /\/.*?\/i?/
  REGEXP2: /\\\\.*?\\\\i?/
  RUNTIME_VAR: /%.*?%/
  
  COMMENT: /\#[^\n]*/
  
negative.code: start: composite+
  
  composite: composite_type composite_body _END
         | metadata
         | validation
  
  composite_body: _composite_item*
  _composite_item: (composite|attr|points|projection|pattern|values|config)
  
  !projection: "PROJECTION"i (string*|AUTO) _END
  !config: "CONFIG"i (string | UNQUOTED_STRING) (string | UNQUOTED_STRING)
  
  !points: "POINTS"i num_pair* _END
  !pattern: "PATTERN"i num_pair* _END
  
  !values: "VALUES"i string_pair* _END
  !metadata: "METADATA"i string_pair* _END
  !validation: "VALIDATION"i string_pair* _END
  
  attr: (UNQUOTED_STRING | composite_type) (value | UNQUOTED_STRING)
  //attr: (UNQUOTED_STRING | SYMBOL | STYLE) (value | UNQUOTED_STRING)
  // STYLE and SYMBOL are listed in composite_type but also attribute names
  
  ?value: string | int | float | expression | not_expression | attr_bind | path
  | regexp | runtime_var | list | NULL | true | false | extent | rgb | hexcolor
  | colorrange | hexcolorrange | num_pair | attr_bind_pair | _attr_keyword
  
  int: SIGNED_INT
  int_pair: int int
  rgb: int int int
  colorrange: int int int int int int
  hexcolorrange: hexcolor hexcolor
  hexcolor: DOUBLE_QUOTED_HEXCOLOR | SINGLE_QUOTED_HEXCOLOR
  
  extent: (int|float) (int|float) (int|float) (int|float) 
  
  !_attr_keyword: "AUTO"i | "HILITE"i | "SELECTED"i 
  
  string: DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING | ESCAPED_STRING
  string_pair: (string|UNQUOTED_STRING) (string|UNQUOTED_STRING)
  
  attr_bind_pair: attr_bind attr_bind
  float: SIGNED_FLOAT
  float_pair: float float
  path: PATH
  regexp: REGEXP1 | REGEXP2
  runtime_var: RUNTIME_VAR
  list: "{" (value | UNQUOTED_STRING) ("," (value | UNQUOTED_STRING))* "}"
  
  num_pair: (int|float) (int|float)
  
  attr_bind: "[" UNQUOTED_STRING "]"
  
  not_expression: ("!"|"NOT"i) expression
  expression: "(" or_test ")"
  ?or_test : (or_test ("OR"i|"||"))? and_test
  ?and_test : (and_test ("AND"i|"&&"))? comparison
  ?comparison: (comparison compare_op)? add
  !compare_op: ">=" | "<" | "=*" | "==" | "=" | "!=" | "~" | "~*" | ">" 
  | "<=" | "IN" | "NE" | "EQ" | "LE" | "LT" | "GE" | "GT"
  
  ?add: (add "+")? (func_call | value)
  // ?multiply: (multiply "*")? (func_call | value)
  
  func_call: UNQUOTED_STRING "(" func_params ")"
  func_params: value ("," value)*
  
  !true: "TRUE"i
  !false: "FALSE"i
  
  !composite_type: "CLASS"i
              | "CLUSTER"i
  