All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bparser.2.13.5.source-code.BParser.scc Maven / Gradle / Ivy

The newest version!
Package de.be4.classicalb.core.parser;

/*******************************************************************
 * Helpers                                                         *
 *******************************************************************/
Helpers
  all_chars = [0 .. 0xffff];
  lf = 10;
  cr = 13;
  unicode_line_seperator = 8232; // \x2028
  unicode_paragraph_seperator = 8233;

  comment_start = '/*';

  triple_quote = 39 39 39;
  single_quote = 39;

  minus = '-' | 0x2212;

  // unicode_letter definition from java-1.7.sablecc by Etienne M. Gagnon, http://sablecc.org/java1.7/
  // but removed unicode lambda 0x03bb from [0x03a3..0x03ce]
  unicode_letter =
    [[[0x0041..0x005a] + [0x0061..0x007a]] + [[0x00aa..0x00aa] + [0x00b5..0x00b5]]] |
    [[[0x00ba..0x00ba] + [0x00c0..0x00d6]] + [[0x00d8..0x00f6] + [0x00f8..0x01f5]]] |
    [[[0x01fa..0x0217] + [0x0250..0x02a8]] + [[0x02b0..0x02b8] + [0x02bb..0x02c1]]] |
    [[[0x02d0..0x02d1] + [0x02e0..0x02e4]] + [[0x037a..0x037a] + [0x0386..0x0386]]] |
    [[[0x0388..0x038a] + [0x038c..0x038c]] + [[[0x038e..0x03a1] + [0x03a3..0x03ba]] + [0x03bc..0x03ce]]] |
    //[[[0x0388..0x038a] + [0x038c..0x038c]] + [[0x038e..0x03a1] + [0x03a3..0x03ce]]] | // removed unicode_lambda 0x03bb
    [[[0x03d0..0x03d6] + [0x03da..0x03da]] + [[0x03dc..0x03dc] + [0x03de..0x03de]]] |
    [[[0x03e0..0x03e0] + [0x03e2..0x03f3]] + [[0x0401..0x040c] + [0x040e..0x044f]]] |
    [[[0x0451..0x045c] + [0x045e..0x0481]] + [[0x0490..0x04c4] + [0x04c7..0x04c8]]] |
    [[[0x04cb..0x04cc] + [0x04d0..0x04eb]] + [[0x04ee..0x04f5] + [0x04f8..0x04f9]]] |
    [[[0x0531..0x0556] + [0x0559..0x0559]] + [[0x0561..0x0587] + [0x05d0..0x05ea]]] |
    [[[0x05f0..0x05f2] + [0x0621..0x063a]] + [[0x0640..0x064a] + [0x0671..0x06b7]]] |
    [[[0x06ba..0x06be] + [0x06c0..0x06ce]] + [[0x06d0..0x06d3] + [0x06d5..0x06d5]]] |
    [[[0x06e5..0x06e6] + [0x0905..0x0939]] + [[0x093d..0x093d] + [0x0958..0x0961]]] |
    [[[0x0985..0x098c] + [0x098f..0x0990]] + [[0x0993..0x09a8] + [0x09aa..0x09b0]]] |
    [[[0x09b2..0x09b2] + [0x09b6..0x09b9]] + [[0x09dc..0x09dd] + [0x09df..0x09e1]]] |
    [[[0x09f0..0x09f1] + [0x0a05..0x0a0a]] + [[0x0a0f..0x0a10] + [0x0a13..0x0a28]]] |
    [[[0x0a2a..0x0a30] + [0x0a32..0x0a33]] + [[0x0a35..0x0a36] + [0x0a38..0x0a39]]] |
    [[[0x0a59..0x0a5c] + [0x0a5e..0x0a5e]] + [[0x0a72..0x0a74] + [0x0a85..0x0a8b]]] |
    [[[0x0a8d..0x0a8d] + [0x0a8f..0x0a91]] + [[0x0a93..0x0aa8] + [0x0aaa..0x0ab0]]] |
    [[[0x0ab2..0x0ab3] + [0x0ab5..0x0ab9]] + [[0x0abd..0x0abd] + [0x0ae0..0x0ae0]]] |
    [[[0x0b05..0x0b0c] + [0x0b0f..0x0b10]] + [[0x0b13..0x0b28] + [0x0b2a..0x0b30]]] |
    [[[0x0b32..0x0b33] + [0x0b36..0x0b39]] + [[0x0b3d..0x0b3d] + [0x0b5c..0x0b5d]]] |
    [[[0x0b5f..0x0b61] + [0x0b85..0x0b8a]] + [[0x0b8e..0x0b90] + [0x0b92..0x0b95]]] |
    [[[0x0b99..0x0b9a] + [0x0b9c..0x0b9c]] + [[0x0b9e..0x0b9f] + [0x0ba3..0x0ba4]]] |
    [[[0x0ba8..0x0baa] + [0x0bae..0x0bb5]] + [[0x0bb7..0x0bb9] + [0x0c05..0x0c0c]]] |
    [[[0x0c0e..0x0c10] + [0x0c12..0x0c28]] + [[0x0c2a..0x0c33] + [0x0c35..0x0c39]]] |
    [[[0x0c60..0x0c61] + [0x0c85..0x0c8c]] + [[0x0c8e..0x0c90] + [0x0c92..0x0ca8]]] |
    [[[0x0caa..0x0cb3] + [0x0cb5..0x0cb9]] + [[0x0cde..0x0cde] + [0x0ce0..0x0ce1]]] |
    [[[0x0d05..0x0d0c] + [0x0d0e..0x0d10]] + [[0x0d12..0x0d28] + [0x0d2a..0x0d39]]] |
    [[[0x0d60..0x0d61] + [0x0e01..0x0e2e]] + [[0x0e30..0x0e30] + [0x0e32..0x0e33]]] |
    [[[0x0e40..0x0e46] + [0x0e81..0x0e82]] + [[0x0e84..0x0e84] + [0x0e87..0x0e88]]] |
    [[[0x0e8a..0x0e8a] + [0x0e8d..0x0e8d]] + [[0x0e94..0x0e97] + [0x0e99..0x0e9f]]] |
    [[[0x0ea1..0x0ea3] + [0x0ea5..0x0ea5]] + [[0x0ea7..0x0ea7] + [0x0eaa..0x0eab]]] |
    [[[0x0ead..0x0eae] + [0x0eb0..0x0eb0]] + [[0x0eb2..0x0eb3] + [0x0ebd..0x0ebd]]] |
    [[[0x0ec0..0x0ec4] + [0x0ec6..0x0ec6]] + [[0x0edc..0x0edd] + [0x0f40..0x0f47]]] |
    [[[0x0f49..0x0f69] + [0x10a0..0x10c5]] + [[0x10d0..0x10f6] + [0x1100..0x1159]]] |
    [[[0x115f..0x11a2] + [0x11a8..0x11f9]] + [[0x1e00..0x1e9b] + [0x1ea0..0x1ef9]]] |
    [[[0x1f00..0x1f15] + [0x1f18..0x1f1d]] + [[0x1f20..0x1f45] + [0x1f48..0x1f4d]]] |
    [[[0x1f50..0x1f57] + [0x1f59..0x1f59]] + [[0x1f5b..0x1f5b] + [0x1f5d..0x1f5d]]] |
    [[[0x1f5f..0x1f7d] + [0x1f80..0x1fb4]] + [[0x1fb6..0x1fbc] + [0x1fbe..0x1fbe]]] |
    [[[0x1fc2..0x1fc4] + [0x1fc6..0x1fcc]] + [[0x1fd0..0x1fd3] + [0x1fd6..0x1fdb]]] |
    [[[0x1fe0..0x1fec] + [0x1ff2..0x1ff4]] + [[0x1ff6..0x1ffc] + [0x207f..0x207f]]] |
    [[[0x2102..0x2102] + [0x2107..0x2107]] + [[0x210a..0x2113] + [0x2115..0x2115]]] |
    [[[0x2118..0x211d] + [0x2124..0x2124]] + [[0x2126..0x2126] + [0x2128..0x2128]]] |
    [[[0x212a..0x2131] + [0x2133..0x2138]] + [[0x3005..0x3005] + [0x3031..0x3035]]] |
    [[[0x3041..0x3094] + [0x309b..0x309e]] + [[0x30a1..0x30fa] + [0x30fc..0x30fe]]] |
    [[[0x3105..0x312c] + [0x3131..0x318e]] + [[0x4e00..0x9fa5] + [0xac00..0xd7a3]]] |
    [[[0xf900..0xfa2d] + [0xfb00..0xfb06]] + [[0xfb13..0xfb17] + [0xfb1f..0xfb28]]] |
    [[[0xfb2a..0xfb36] + [0xfb38..0xfb3c]] + [[0xfb3e..0xfb3e] + [0xfb40..0xfb41]]] |
    [[[0xfb43..0xfb44] + [0xfb46..0xfbb1]] + [[0xfbd3..0xfd3d] + [0xfd50..0xfd8f]]] |
    [[[0xfd92..0xfdc7] + [0xfdf0..0xfdfb]] + [[0xfe70..0xfe72] + [0xfe74..0xfe74]]] |
    [[[0xfe76..0xfefc] + [0xff21..0xff3a]] + [[0xff41..0xff5a] + [0xff66..0xffbe]]] |
    [[[0xffc2..0xffc7] + [0xffca..0xffcf]] + [[0xffd2..0xffd7] + [0xffda..0xffdc]]];

  // not used yet:
  //unicode_digit =
  //  [[[0x0030..0x0039] + [0x0660..0x0669]] + [[0x06f0..0x06f9] + [0x0966..0x096f]]] |
  //  [[[0x09e6..0x09ef] + [0x0a66..0x0a6f]] + [[0x0ae6..0x0aef] + [0x0b66..0x0b6f]]] |
  //  [[[0x0be7..0x0bef] + [0x0c66..0x0c6f]] + [[0x0ce6..0x0cef] + [0x0d66..0x0d6f]]] |
  //  [[[0x0e50..0x0e59] + [0x0ed0..0x0ed9]] + [[0x0f20..0x0f29] + [0xff10..0xff19]]];

  unicode_superscripts = [0x2070..0x2079]; // TODO: add 185,178,179
  unicode_subscripts = [0x2080..0x2089];
  unicode_prime = [0x2032 + [8216..8217]]; // 0x2032=8242 ' primes / quotes // TODO: add hats

  digit = ['0' .. '9'];
  hexdigit = [[digit + ['a' .. 'f']] + ['A' .. 'F']];

  line_break = [[[lf + cr] + unicode_line_seperator] + unicode_paragraph_seperator]; // newline
  layout_char = [[9 + 32] + 160];
  // 160: non-breaking space
  white_space = line_break | layout_char+;

  single_line_string_char = [all_chars - line_break];
  string_literal = '"' ([single_line_string_char - ['"' + '\']] | '\' single_line_string_char)* '"';
  // backquote to generate identifiers with special symbols or which clash with keywords
  quoted_identifier_literal = '`' ([single_line_string_char - ['`' + '\']] | '\' single_line_string_char)* '`';

  unicode_lambda = 0x03bb | 0x1d706; // 120582 in decimal; generated in Jupyter when pretty printing
  regular_identifier_literal = (unicode_letter) (unicode_letter | unicode_lambda | digit | '_')* (unicode_subscripts)* (unicode_prime)*; // B identifiers, where we allow subscripts and Unicode quotes at the end
  identifier_literal = regular_identifier_literal | quoted_identifier_literal;

  pragma_prefix = '/*@' layout_char*;
  pragma_identifier_literal = ([[0x21 .. 0x7e] - [['"' + '`'] + '*']] | unicode_letter)+;
  // we could try and also allow '*', note: if we allow whitespace then the pragma keywords are no longer
  // accepted due to the maximal munching
  // versions below do not work:
  // layout_char_with_ws = [[[0 .. 32] + [127..160]] + [[8206 .. 8207] + [8232 .. 8233]]];
  // pragma_identifier_literal = ([all_chars - [layout_char_with_ws + '*']]+ ('*' [all_chars - [layout_char_with_ws + '/']])?)* '*'?;


/*******************************************************************
 * States                                                          *
 *******************************************************************/
States
  // Initial state in which the lexer recognizes only keywords that start a model.
  // The internal keywords for special parsing modes (#EXPRESSION, etc. - see below)
  // are recognized only in this start state.
  // This avoids conflicts with the symbol # (existential quantification) in regular B syntax.
  // After the first keyword has been lexed,
  // the parser switches to the normal state and never returns to the start state.
  start,
  normal,
  // Multiline constructs (block comments, pragmas, multiline strings) have their own lexer states
  // to provide better errors when the closing delimiter is missing.
  // If e. g. block comments were parsed as a single token,
  // then a long unclosed block comment would cause a pushback buffer overflow:
  // the lexer first tries to lex the entire remaining text as a block comment,
  // but once EOF is reached,
  // it tries to backtrack all the way to the start of the comment.
  // This is not an issue for line comments,
  // because EOF is a valid line comment terminator.
  block_comment,
  multiline_string,
  pragma_description_content,
  pragma_content,
  multiline_template;

/*******************************************************************
 * Tokens                                                          *
 *******************************************************************/
Tokens
  {start->normal,normal} shebang = '#!' [all_chars - line_break]* line_break?;

  {start->normal,normal} line_comment = '//' [all_chars - line_break]* line_break?;

  {pragma_content->normal,pragma_description_content->normal} pragma_end = '*/';
  {start->pragma_content,normal->pragma_content} pragma_generated = pragma_prefix 'generated'; // we could enforce nothing follows it
  {start->pragma_content,normal->pragma_content} pragma_symbolic = pragma_prefix 'symbolic'; // ditto
  {start->pragma_content,normal->pragma_content} pragma_label = pragma_prefix 'label';
  {start->pragma_content,normal->pragma_content} pragma_file = pragma_prefix 'file';
  {start->pragma_content,normal->pragma_content} pragma_package = pragma_prefix 'package';
  {start->pragma_description_content,normal->pragma_description_content} pragma_description = pragma_prefix 'desc';
  {start->pragma_content,normal->pragma_content} pragma_import_package = pragma_prefix 'import-package';
  {start->block_comment,normal->block_comment} unrecognised_pragma = pragma_prefix;

  // content of description pragma
  // A single pragma_free_text token is either all whitespace or all non-whitespace.
  // This simplifies removing leading/trailing whitespace from the description text later.
  {pragma_description_content} pragma_free_text = [[all_chars - '*'] - [line_break + layout_char]]* | '*' | white_space;

  // the pragma_content state collects attributes for label and file pragmas
  {pragma_content} pragma_id_or_string = string_literal | pragma_identifier_literal;

  {start->block_comment, normal->block_comment} comment = comment_start; // comment_start helper is a workaround to force SableCC to allow modifying text of comment tokens.
  {block_comment->normal} comment_end = '*/';
  {block_comment} comment_body = [all_chars - '*']*;
  {block_comment} star = '*';

  {normal->multiline_string} multiline_string_start = triple_quote;
  {multiline_string->normal} multiline_string_end = triple_quote;
  // One or two single quotes followed by a different character don't terminate the string.
  {multiline_string} multiline_string_content = ((single_quote single_quote?)? [all_chars - [single_quote + '\']] | '\' all_chars)*;

  {normal->multiline_template} multiline_template_start = '```';
  {multiline_template->normal} multiline_template_end = '```';
  // One or two backquotes followed by a different character don't terminate the string.
  {multiline_template} multiline_template_content = (('`' '`'?)? [all_chars - ['`' + '\']] | '\' all_chars)*;

  {normal} string_literal = string_literal;
  {normal} for_any = '!' | 0x2200;
  {normal} exists = '#' | 0x2203;
  {normal} b_prime = '$0';
  {normal} lambda = '%' | unicode_lambda;
  {normal} conjunction = '&' | 0x2227; // 0x2227 Unicode wedge
  {normal} illegal_unicode_symbol = 0x22c0 | //  0x22c0 = 8896 is n-ary conjunction, not normal conjunction
              0x22c1 | // n-ary disjunction
              0x2204 | // not exists
              0x228e | // multi-set union bags
              0x22a2 | 0x22a6 | 0x22a7 | // models / entails / sequent / turnstyle operators
              0x21d0 | 0x27f8 | // inverse implies; we do not handle it in grammar because associativity not clear
              0x220a | 0x220d; // small element of and contains operators
  {normal} single_quotation = 39; // single quote: '
  {normal} left_par = '('; // opening/left parenthesis
  {normal} right_par = ')'; // closing/right parenthesis
  {normal} product = '*' | 0x2217; // Unicode asterisk operator; used in Camille in Rodin
  {normal} cartesian_product = 0x00d7 | // 215 decimal; used in rodin
                               0x2a2f; // vector or cross product, used in IDP-Z3
  {normal} power_of = '**' | 0x02c4; // variation of ^ in Unicode; up-arrow used for sequence restrict_front below
  {normal} plus = '+';
  {normal} partial_function = '+' minus '>' | 0x21f8;
  {normal} partial_surjection = '+' minus '>>' | 0x2900;
  {normal} comma = ',';
  {normal} minus = minus;
  {normal} total_function = minus minus '>' | 0x2192;
  {normal} total_surjection = minus minus '>>' | 0x21a0;
  {normal} insert_start_sequence = minus '>' | 0x21fe;
  {normal} dot = '.' ; // Ascii dot
  {normal} dot2 = '·' | 0x22c5 | '•'; // is the bullet, Option-8 on US keyboards
   // seperate from dot below to avoid shift-reduce conflicts for event-b comprehension with composed identifiers
  {normal} interval = '..' | 0x2025;
  {normal} division = '/' | 0xf7;
  {normal} finite = '@finite'; // Event-B finite predicate (ProB-specific syntax)
  {normal} partition = '@partition'; // Event-B partition predicate (ProB-specific syntax)
  {normal} not_belonging = '/:' | 0x2209;
  {normal} non_inclusion = '/<:' | 0x2288;
  {normal} strict_non_inclusion = '/<<:' | 0x2284;
  {normal} not_equal = '/=' | 0x2260;
  {normal} set_subtraction = '\' | 0x2216; // decimal 8726, used in Rodin
  {normal} intersection = '/\' | 0x2229;
  {normal} restrict_head_sequence = '/|\' | 0x2191;    // unicode uparrow for restrict_front operator
  {normal} element_of = ':' | 0x2208;
  {normal} double_colon = '::' | ':' 0x2208; /* becomes_element_of */
    // Note TLA+ propses 0x2237 (PROPORTION) for label_as operator ::
  {normal} assign = ':=' | 0x2254; //8788 decimal, used in Rodin and proposed for TLA+
  {normal} semicolon = ';'; // separator, sequential composition and also forward composition (is 0x3b)
  {normal} less = '<';
  {normal} ring = 0x2218; // circ or backward composition from Event-B, normally not allowed by Atelier-B
  {normal} less_greater = '<' white_space* '>'; // for empty sequence
  {normal} overwrite_relation = '<+' | 0xe103 | 0x22d6; /* 0xe103 is EventB Style override, 0x22d6 is the AtelierB version */
  {normal} set_relation = '<' minus '>' | 0x2194;
  {normal} insert_end_sequence = '<-' | 0x21fd;
  {normal} output_parameters = '<--' | 0x2190 | 0x27f5; // 2190: Leftwards Arrow; 27f5: Long Leftwards Arrow proposed in https://github.com/tlaplus-community/tlaplus-standard
  {normal} inclusion = '<:' | 0x2286;
  {normal} strict_inclusion = '<<:' | 0x2282 | 0x228a; // 0x228a actually less ambiguous mathematically, see
         // https://math.stackexchange.com/questions/1038233/subset-of-above-not-equal-to-subsetneqq-symbol
  {normal} superset = 0x2287; // no ASCII syntax
  {normal} superset_strict = 0x2283; // no ASCII syntax
  {normal} not_superset_strict = 0x2285 | 0x228b; // no ASCII syntax, 228b has struck-through equal sign
  {normal} not_superset = 0x2289; // no ASCII syntax
  {normal} contains_element = 0x220b; // no ASCII syntax, inverted element of symbol
  {normal} not_contains_element = 0x220c; // no ASCII syntax
  {normal} domain_subtraction = '<<|' | 0x2a64 | 0x25c0;
  {normal} less_equal = '<=' | 0x2264;
  {normal} equivalence = '<=>' | 0x21d4 | 0x27fa;  // 0x21d4 is LEFT RIGHT DOUBLE ARROW; TLA proposes 0x27fa (LONG LEFT RIGHT DOUBLE ARROW) for iff
    // there also is \equiv with 0x2261 (IDENTICAL TO)
  {normal} domain_restriction = '<|' | 0x25c1;
  {normal} equal = '=';
  {normal} double_equal = '==' | 0x225c; // == , Unicode DELTA EQUAL TO proposed in https://github.com/tlaplus-community/tlaplus-standard
  {normal} implies = '=>' | 0x21d2 | 0x27f9;  // 0x21d2 is RIGHTWARDS DOUBLE ARROW; TLA proposes 0x27f9 (LONG RIGHTWARDS DOUBLE ARROW)
  {normal} greater = '>';
  {normal} partial_injection = '>+>' | 0x2914;
  {normal} total_injection = '>' minus '>' | 0x21a3;  // >->
  {normal} partial_bijection = '>+>>';
  {normal} total_bijection = '>' minus '>>' | 0x2916; // >->>
  {normal} direct_product = '><' | 0x2297;
  {normal} greater_equal = '>=' | 0x2265;
  {normal} abstract_constants = 'ABSTRACT_CONSTANTS';
  {normal} abstract_variables = 'ABSTRACT_VARIABLES';
  {normal} any = 'ANY';
  {normal} assert = 'ASSERT';
  {normal} assertions = 'ASSERTIONS';
  {normal} be = 'BE';
  {normal} begin = 'BEGIN';
  {normal} bool = 'BOOL'
               |  0x1d539; // BOOL B bool_set symbol, similar to NATURAL N or INTEGER Z symbol; used by IDP-Z3
  {normal} bfalse = 'bfalse' | 0x22A5; // falsity
  {normal} case = 'CASE';
  {normal} choice = 'CHOICE';
  {normal} concrete_constants = 'CONCRETE_CONSTANTS';
  {normal} concrete_variables = 'CONCRETE_VARIABLES';
  {normal} constants = 'CONSTANTS';
  {normal} constraints = 'CONSTRAINTS';
  {start->normal,normal} definitions = 'DEFINITIONS';
  {normal} expressions = 'EXPRESSIONS';
  {normal} predicates = 'PREDICATES';
  {normal} do = 'DO';
  {normal} either = 'EITHER';
  {normal} else = 'ELSE';
  {normal} elsif = 'ELSIF';
  {normal} end = 'END';
  {normal} extends = 'EXTENDS';
  {normal} false = 'FALSE'; // now reserved for falsity | 0x22a5;
  {normal} fin = 'FIN';
  {normal} fin1 = 'FIN1'; // add 'FIN'0x8321 ?
  {normal} if = 'IF';
  {start->normal,normal} implementation = 'IMPLEMENTATION';
  {normal} imports = 'IMPORTS';
  {normal} in = 'IN';
  {normal} includes = 'INCLUDES';
  {normal} initialisation = 'INITIALISATION' | 'INITIALIZATION'; /* amerikanische Version scheinbar auch erlaubt */
  {normal} int = 'INT';
  {normal} integer = 'INTEGER' | 0x2124;
  {normal} real = 'REAL' | 0x211D;
  {normal} float = 'FLOAT';
  {normal} quantified_inter = 'INTER' | 0x22c2; // 0x22c2 is the n-ary intersection symbol
  {normal} invariant = 'INVARIANT';
  {normal} let = 'LET';
  {normal} local_operations = 'LOCAL_OPERATIONS';
  {start->normal,normal} machine = 'MACHINE';
  {start->normal,normal} model = 'MODEL';
  {start->normal,normal} system = 'SYSTEM'; /* SYSTEM fuer Event-B */
  {normal} max_int = 'MAXINT';
  {normal} min_int = 'MININT';
  {normal} nat = 'NAT';
  {normal} nat1 = 'NAT1';
  {normal} natural = 'NATURAL' | 0x2115;
  {normal} natural1 = 'NATURAL1' | 0x2115 0x0031 | 0x2115 0x2081;
  {normal} of = 'OF';
  {normal} operations = 'OPERATIONS' | 'EVENTS'; /* EVENTS fuer Event-B */
  {normal} or = 'OR';
  {normal} pi = 'PI' | 0x220f;
  {normal} pow = 'POW' | 0x2119;
  {normal} pow1 = 'POW1' | 0x2119 0x0031 | 0x2119 0x2081;
  {normal} pre = 'PRE';
  {normal} promotes = 'PROMOTES';
  {normal} properties = 'PROPERTIES';
  {normal} refines = 'REFINES';
  {start->normal,normal} refinement = 'REFINEMENT';
  {normal} sees = 'SEES';
  {normal} select = 'SELECT';
  {normal} sets = 'SETS';
  {normal} sigma = 'SIGMA' | 0x2211;
  {normal} string = 'STRING';
  {normal} then = 'THEN';
  {normal} true = 'TRUE'; // now reserved for truth: | 0x22a4
  {normal} quantified_union = 'UNION' | 0x22c3; // 0x22c3 is the n-ary union symbol
  {normal} uses = 'USES';
  {normal} value = 'VALUES';
  {normal} var = 'VAR';
  {normal} variant = 'VARIANT';
  {normal} variables = 'VARIABLES';
  {normal} when = 'WHEN';
  {normal} where = 'WHERE';
  {normal} while = 'WHILE';
  {normal} witness_kw = 'WITNESS';
  {normal} left_bracket = '[';
  {normal} right_bracket = ']';
  {normal} union = '\/' | 0x222a;
  {normal} restrict_tail_sequence = '\|/' | 0x2193;
  {normal} concat_sequence = '^' | 0x2312;
  {normal} bool_cast = 'bool';
  {normal} card = 'card';
  {normal} convert_int_floor = 'floor';
  {normal} convert_int_ceiling = 'ceiling';
  {normal} convert_real = 'real';
  {normal} closure = 'closure';
  {normal} closure1 = 'closure1'; // add 'closure' 0x8321 ?
  {normal} conc = 'conc';
  {normal} dom = 'dom';
  {normal} first = 'first';
  {normal} fnc = 'fnc';
  {normal} front = 'front';
  {normal} id = 'id';
  {normal} generalized_inter = 'inter';
  {normal} iseq = 'iseq';
  {normal} iseq1 = 'iseq1'; // add 'iseq'0x8321 ?
  {normal} iterate = 'iterate';
  {normal} last = 'last';
  {normal} max = 'max';
  {normal} min = 'min';
  {normal} mod = 'mod';
  {normal} not = 'not' | 0x00ac;
  {normal} logical_or = 'or' | 0x2228;  // disjunction, 0x2228=8744 is Unicode vee inserted by macOS symbol table
  {normal} perm = 'perm';
  {normal} pred = 'pred';
  {normal} prj1 = 'prj1';
  {normal} prj2 = 'prj2';
  {normal} prj1_v2 = '@prj1'; // prj1 which requires no arguments, typechecker infers type
  {normal} prj2_v2 = '@prj2'; // ditto; TODO: find better keyword or detect prj1/prj2 differently
  {normal} ran = 'ran';
  {normal} rec = 'rec';
  {normal} rel = 'rel';
  {normal} rev = 'rev';
  {normal} seq = 'seq';
  {normal} seq1 = 'seq1'; // add | 'seq'0x8321 ?
  {normal} size = 'size';
  {normal} skip = 'skip';
  {normal} struct = 'struct';
  {normal} succ = 'succ';
  {normal} tail = 'tail';
  {normal} generalized_union = 'union';
  {normal} empty_set = 0x2205;
  {normal} left_brace = '{';
  {normal} right_brace = '}';
  {normal} vertical_bar = '|' | 0x2223; // Unicode divides; generated by Rodin
  {normal} double_vertical_bar = '||' | 0x2225 | 0x2016; // 2225 Parallel To; 2016: Double Vertical Line
  {normal} maplet = '|->' | 0x21a6; // TLA+ proposes 0x27fc (LONG RIGHTWARDS ARROW FROM BAR) for all_map_to |->
  {normal} range_restriction = '|>' | 0x25b7;
  {normal} range_subtraction = '|>>' | 0x2a65 | 0x25b6;
  {normal} tilde = '~' | 0x223c | 0x207b 0xb9; // coming from Rodin
  {normal} oftype = 0x2982; // coming from Rodin; we do not support the ASCII version oftype (yet)

  // Extensions (see https://wiki.event-b.org/index.php/Rodin_Keyboard_User_Guide)
  {normal} total_relation = '<<' minus '>' | 0xe100;             // <<->
  {normal} surjection_relation = '<' minus '>>' | 0xe101;        // <->>
  {normal} total_surjection_relation = '<<' minus '>>' | 0xe102; // <<->>
  {normal} kw_freetypes = 'FREETYPES';

  // keywords for special parsing modes;
  // these # keywords do not interfere with normal parsing
  {start->normal} kw_expression = '#EXPRESSION';
  {start->normal} kw_predicate = '#PREDICATE';
  {start->normal} kw_formula = '#FORMULA';
  {start->normal} kw_substitution = '#SUBSTITUTION';
  {start->normal} kw_oppattern = '#OPPATTERN';
  {start->normal} kw_machine_clause = '#MACHINECLAUSE';

  {normal} truth_predicate = 'btrue' | 0x22A4; // truth, no longer accept #truth_predicate
  {start->normal,normal} identifier_literal = identifier_literal; // Also allowed in start state because of rules DSL - the RULES_MACHINE keyword is parsed as an identifier before RulesGrammar transforms it.
  {normal} integer_literal = digit+;
  {normal} real_literal = digit+ '.' digit+ ('E' | 'e') ('+' | '-')? digit+ | digit+ '.' digit+;
  {normal} hex_literal = '0x' hexdigit+; // currently BLexer.java replaces THexLiteral with TIntegerLiteral

  {normal} underscore = '_';

  {start,normal,pragma_content} white_space = white_space;

  // The following tokens are never recognized by the lexer because they are declared below identifier_literal.

  // Dummy tokens for non-expression definitions.
  // The corresponding syntax nodes are generated by Java code (by BLexer using PreParser definition list).
  {normal} def_literal_substitution = identifier_literal;
  {normal} def_literal_predicate = identifier_literal;

  // Grammar extensions.
  // The keywords should be synchronized with RulesGrammar.java.
  {normal} kw_rule = 'RULE';
  {normal} kw_substitution_operator = identifier_literal;
  {normal} kw_predicate_operator = identifier_literal;
  {normal} kw_expression_operator = identifier_literal;
  {normal} kw_predicate_attribute = identifier_literal;
  {normal} kw_attribute_identifier = identifier_literal;
  {normal} kw_for = 'FOR';
  {normal} kw_rule_for_all = 'RULE_FORALL';
  {normal} kw_rule_fail = 'RULE_FAIL';
  {normal} kw_rule_error_type = 'ERROR_TYPE';
  {normal} kw_expect = 'EXPECT';
  {normal} kw_computation = 'COMPUTATION';
  {normal} kw_define = 'DEFINE';
  {normal} kw_type = 'TYPE';
  {normal} kw_value = 'VALUE';
  {normal} kw_body = 'BODY';
  {normal} kw_dummy_value = 'DUMMY_VALUE';
  {normal} kw_on_success = 'ON_SUCCESS';
  {normal} kw_counterexample = 'COUNTEREXAMPLE';
  {normal} kw_function = 'FUNCTION';
  {normal} kw_references = 'REFERENCES';

/*******************************************************************
 * Ignored Tokens                                                  *
 *******************************************************************/
Ignored Tokens
  white_space,
  comment, comment_body, star, comment_end,
  unrecognised_pragma,
  line_comment;

/*******************************************************************
 * Productions                                                     *
 *******************************************************************/
//[0,0] Production ... doesn't exist in section AST
// Such an error message indicates that a vertical bar '|' is followed by a semicolon ';'.
Productions

parse_unit {-> parse_unit} =
  {machine} shebang? P.machine {-> machine.parse_unit} |
  {definition_file} shebang? [clause]:definitions_clause {-> New parse_unit.definition_file(clause.machine_clause)} |
  {predicate} kw_predicate [pred]:predicate_top {-> New parse_unit.predicate(pred.predicate)} |
  {expression} kw_expression [expr]:expression_or_id_list {-> New parse_unit.expression(expr.expression)} |
  {predformula} kw_formula [pred]:predicate_top {-> New parse_unit.predicate(pred.predicate)} |
  {exprformula} kw_formula [expr]:expression_or_id_list {-> New parse_unit.expression(expr.expression)} |
  {substitution} kw_substitution [subst]:substitution_l1 {-> New parse_unit.substitution(subst.substitution)} |
  {oppattern} kw_oppattern [pattern]:operation_pattern {-> pattern.parse_unit} |
  {machine_clause} kw_machine_clause [clause]:machine_clause {-> New parse_unit.machine_clause(clause.machine_clause)}; // used to single machine clauses

machine {-> parse_unit} =
  machine_x {-> machine_x.parse_unit} |
  {generated} pragma_generated pragma_end [lower]:P.machine {-> New parse_unit.generated(lower.parse_unit)} |
  {package} pragma_package [package]:pragma_id_or_string pragma_end [imports]:import_package_list? [parse_unit]:P.machine
    {-> New parse_unit.package(package, [imports.import_package], parse_unit.parse_unit)};

import_package_list {-> import_package*} =
  {single} pragma_import_package [package_or_machine]:pragma_id_or_string pragma_end {-> [New import_package(package_or_machine)]} |
  {multiple} [rest]:import_package_list pragma_import_package [package_or_machine]:pragma_id_or_string pragma_end {-> [rest.import_package, New import_package(package_or_machine)]};


machine_x {-> parse_unit} =
  {abstract} [variant]: machine_variant [header]:machine_header [machine_clauses]:machine_clause_list? end {-> New parse_unit.abstract_machine(variant, header.machine_header, [machine_clauses.machine_clause])} |
  {refinement} T.refinement [header]:machine_header refines [ref_machine]:identifier_literal [machine_clauses]:machine_clause_list? end {-> New parse_unit.refinement_machine(header.machine_header, ref_machine, [machine_clauses.machine_clause])} |
  {implementation} T.implementation [header]:machine_header refines [ref_machine]:identifier_literal [machine_clauses]:machine_clause_list? end {-> New parse_unit.implementation_machine(header.machine_header, ref_machine, [machine_clauses.machine_clause])};

machine_variant {-> machine_variant} =
  {machine} T.machine {-> New machine_variant.machine()} |
  {model} T.model {-> New machine_variant.model()} |
  {system} T.system {-> New machine_variant.system()};

machine_header {-> machine_header} =
  [name]:composed_identifier [parameters]:machine_params? {-> New machine_header([name.identifier_literal], [parameters.expression])};

machine_params {-> expression*} = left_par [param_list]:machine_param_list right_par {-> [param_list.expression]};

machine_param_list {-> expression*} =
  {single} [param]:machine_param {-> [param.expression]} |
  {multi} [rest]:machine_param_list comma [first]:machine_param {-> [rest.expression, first.expression]};

machine_param {-> expression} = [parameter]:expression_in_par {-> parameter.expression};

machine_clause_list {-> machine_clause*} =
  {single} [clause]:machine_clause {-> [clause.machine_clause]} |
  {multiple} [rest]:machine_clause_list [clause]:machine_clause {-> [rest.machine_clause, clause.machine_clause]};

machine_clause {-> machine_clause} =
  {definitions} [clause]:definitions_clause {-> clause.machine_clause} |
  {constraints} [clause]:constraints_clause {-> clause.machine_clause} |
  {sees} [clause]:sees_clause {-> clause.machine_clause} |
  {promotes} [clause]:promotes_clause {-> clause.machine_clause} |
  {uses} [clause]:uses_clause {-> clause.machine_clause} |
  {includes} [clause]:includes_clause {-> clause.machine_clause} |
  {extends} [clause]:extends_clause {-> clause.machine_clause} |
  {imports} [clause]:imports_clause {-> clause.machine_clause} |
  {sets} [clause]:sets_clause {-> clause.machine_clause} |
  {constants} [clause]:constants_clause {-> clause.machine_clause} |
  {abstract_constants} [clause]:abstract_constants_clause {-> clause.machine_clause} |
  {properties} [clause]:properties_clause {-> clause.machine_clause} |
  {concrete_variables} [clause]:concrete_variables_clause {-> clause.machine_clause} |
  {variables} [clause]:variables_clause {-> clause.machine_clause} |
  {assertions} [clause]:assertions_clause {-> clause.machine_clause} |
  {initialisation} [clause]:initialisation_clause {-> clause.machine_clause} |
  {local_operations} [clause]:local_operations_clause {-> clause.machine_clause} |
  {operations} [clause]:operations_clause {-> clause.machine_clause} |
  {values} [clause]:values_clause {-> clause.machine_clause} |
  {invariant} [clause]:invariant_clause {-> clause.machine_clause} |
  {freetypes} [clause]:freetypes_clause {-> clause.machine_clause} |
  {references} [clause]:references_clause {-> clause.machine_clause} |
  {expressions} [clause]:expressions_clause {-> clause.machine_clause} |
  {predicate} [clause]:predicates_clause {-> clause.machine_clause};

expressions_clause {-> machine_clause} = expressions [expression_def_list]:expression_def_list semicolon?
   {-> New machine_clause.expressions([expression_def_list.expression_definition])};
predicates_clause {-> machine_clause} = predicates [predicate_def_list]:predicate_def_list semicolon?
   {-> New machine_clause.predicates([predicate_def_list.predicate_definition])};

definitions_clause {-> machine_clause} = definitions [definition_list]:definition_list semicolon? {-> New machine_clause.definitions([definition_list.definition])};

expression_def_list {-> expression_definition*} =
  {single} [def]:expression_def {-> [def.expression_definition]} |
  {multi} [rest]:expression_def_list semicolon [def]:expression_def {-> [rest.expression_definition, def.expression_definition]};

predicate_def_list {-> predicate_definition*} =
  {single} [def]:predicate_def {-> [def.predicate_definition]} |
  {multi} [rest]:predicate_def_list semicolon [def]:predicate_def {-> [rest.predicate_definition, def.predicate_definition]};

definition_list {-> definition*} =
  {single} [def]:definition {-> [def.definition]} |
  {multi} [rest]:definition_list semicolon [def]:definition {-> [rest.definition, def.definition]};

expression_def {-> expression_definition} =
  [name]:identifier_literal [parameters]:def_parameters? double_equal [rhs]:expression_or_id_list
     {-> New expression_definition(name, [parameters.expression], rhs.expression)};

predicate_def {-> predicate_definition} =
  [name]:identifier_literal [parameters]:def_parameters? double_equal [rhs]:predicate_top
     {-> New predicate_definition(name, [parameters.expression], rhs.predicate)};

definition {-> definition} =
  {predicate} [name]:def_literal_predicate [parameters]:def_parameters? double_equal [rhs]:predicate_top
      {-> New definition.predicate_definition(name, [parameters.expression], rhs.predicate)}
      |
  {substitution} [name]:def_literal_substitution [parameters]:def_parameters? double_equal [rhs]:substitution_l3
      {-> New definition.substitution_definition(name, [parameters.expression], rhs.substitution)}
       |
  {expression} [name]:identifier_literal [parameters]:def_parameters? double_equal [rhs]:expression_or_id_list
      {-> New definition.expression_definition(name, [parameters.expression], rhs.expression)}
        |
  {file} [filename]:string_literal
      {-> New definition.file_definition(filename)};

normal_identifier_expression {-> expression} =
  {identifier} [identifier]:identifier_literal {-> New expression.identifier([identifier])};

// a list of normal identifiers (without dot prefixes)
normal_identifier_expression_list {-> expression*} =
    [first]:normal_identifier_expression [rest]:normal_identifier_expression_list_tail* {-> [first.expression, rest.expression]};
normal_identifier_expression_list_tail {-> expression} =
    comma [expr]:normal_identifier_expression {-> expr.expression};

// allow either a top-level expression (with optional desc pragmas) or an identifier list (treated as a couple)
  // Idea to allow identifier lists in DEFINITIONs:
  // note: expression_list instead of normal_identifier_expression_list also works
  // Note: it is also important to adapt kw_formula grammar rule to allow identifier lists
  //       as PreParser.java method determineType will parse rhs using this to determine type of definition
expression_or_id_list {-> expression} =
  {id_list} [first]:normal_identifier_expression comma [rest]:normal_identifier_expression_list
            {->  New expression.couple([first.expression, rest.expression])} |
  {expr} [expr]:expression_top_with_opt_desc  {-> expr.expression};

def_parameters {-> expression*} = left_par [parameters]:identifier_declaration_list right_par {-> [parameters.expression]};

sees_clause {-> machine_clause} = sees [machine_names]:machine_reference_no_params_list {-> New machine_clause.sees([machine_names.machine_reference_no_params])};

references_clause {-> machine_clause} = kw_references [machine_references]:machine_ref_list {-> New machine_clause.references([machine_references.machine_reference])};

promotes_clause {-> machine_clause} = promotes [operation_names]:operation_reference_list {-> New machine_clause.promotes([operation_names.operation_reference])};

uses_clause {-> machine_clause} = uses [machine_names]:machine_reference_no_params_list {-> New machine_clause.uses([machine_names.machine_reference_no_params])};

includes_clause {-> machine_clause} = includes [machine_references]:machine_ref_list {-> New machine_clause.includes([machine_references.machine_reference])};

extends_clause {-> machine_clause} = extends [machine_references]:machine_ref_list {-> New machine_clause.extends([machine_references.machine_reference])};

imports_clause {-> machine_clause} = imports [machine_references]:machine_ref_list {-> New machine_clause.imports([machine_references.machine_reference])};

machine_ref_list {-> machine_reference*} =
  {single} [ref]:machine_reference {-> [ref.machine_reference]} |
  {multi} [rest]:machine_ref_list comma [first]:machine_reference {-> [rest.machine_reference, first.machine_reference]};

machine_reference {-> machine_reference} =
  {simple} [machine_reference]:machine_reference2 {-> machine_reference.machine_reference} |
  {file} [machine_reference]:machine_reference2 pragma_file [file]:pragma_id_or_string pragma_end
    {-> New machine_reference.file(machine_reference.machine_reference, file)};

machine_reference2 {-> machine_reference} =
  {simple} [machine_name]:composed_identifier [parameters]:machine_params? {-> New machine_reference([machine_name.identifier_literal], [parameters.expression])};

machine_reference_no_params_list {-> machine_reference_no_params*} =
  {single} [ref]:machine_reference_no_params {-> [ref.machine_reference_no_params]} |
  {multi} [rest]:machine_reference_no_params_list comma [last]:machine_reference_no_params {-> [rest.machine_reference_no_params, last.machine_reference_no_params]};

machine_reference_no_params {-> machine_reference_no_params} =
  {simple} [ref]:machine_reference_no_params2 {-> ref.machine_reference_no_params} |
  {file} [ref]:machine_reference_no_params2 pragma_file [file]:pragma_id_or_string pragma_end {-> New machine_reference_no_params.file(ref.machine_reference_no_params, file)};

machine_reference_no_params2 {-> machine_reference_no_params} =
  {simple} [machine_name]:composed_identifier {-> New machine_reference_no_params([machine_name.identifier_literal])};

operation_reference_list {-> operation_reference*} =
  {single} [ref]:operation_reference {-> [ref.operation_reference]} |
  {multi} [rest]:operation_reference_list comma [last]:operation_reference {-> [rest.operation_reference, last.operation_reference]};

operation_reference {-> operation_reference} = [operation_name]:composed_identifier {-> New operation_reference([operation_name.identifier_literal])};

description_pragma {-> description_pragma} =
  pragma_description [parts]:pragma_free_text* pragma_end {-> New description_pragma([parts])};

variables_clause {-> machine_clause} =
  {abstract} abstract_variables [identifiers]:identifier_declaration_list {-> New machine_clause.variables([identifiers.expression])} |
  variables [identifiers]:identifier_declaration_list {-> New machine_clause.variables([identifiers.expression])};

constants_clause {-> machine_clause} =
  {concrete} concrete_constants [identifiers]:identifier_declaration_list {-> New machine_clause.constants([identifiers.expression])} |
  constants [identifiers]:identifier_declaration_list {-> New machine_clause.constants([identifiers.expression])};

concrete_variables_clause {-> machine_clause} = concrete_variables [identifiers]:identifier_declaration_list {-> New machine_clause.concrete_variables([identifiers.expression])};

abstract_constants_clause {-> machine_clause} = abstract_constants [identifiers]:identifier_declaration_list {-> New machine_clause.abstract_constants([identifiers.expression])};

sets_clause {-> machine_clause} = sets [set_definitions]:set_def_list {-> New machine_clause.sets([set_definitions.set])};

set_def_list {-> set*} =
  {single} [set]:set {-> [set.set]} |
  {multi} [rest]:set_def_list semicolon [last]:set {-> [rest.set, last.set]};

set {-> set} =
  {description} [set]:set [description]:description_pragma {-> New set.description(description.description_pragma, set)} |
  {deferred} [identifier]:composed_identifier {-> New set.deferred_set([identifier.identifier_literal])} |
  {enumerated} [identifier]:composed_identifier equal left_brace [elements]:identifier_declaration_list right_brace {-> New set.enumerated_set([identifier.identifier_literal], [elements.expression])} |
  {enumerated_set_via_def} [identifier]:composed_identifier equal [elem_def]:composed_identifier  // covers:  SETS Id = ED; DEFINITIONS ED == {a,b,c}
          {-> New set.enumerated_set_via_def([identifier.identifier_literal], [elem_def.identifier_literal])};
  // TO DO: allow description pragmas for enumerated set elements

properties_clause {-> machine_clause} = properties [predicates]:predicate_top {-> New machine_clause.properties(predicates.predicate)};

initialisation_clause {-> machine_clause} = initialisation [substitutions]:substitution_l1 {-> New machine_clause.initialisation(substitutions.substitution)};

invariant_clause {-> machine_clause} = invariant [predicates]:predicate_top {-> New machine_clause.invariant(predicates.predicate)};

constraints_clause {-> machine_clause} = constraints [predicates]:predicate_top {-> New machine_clause.constraints(predicates.predicate)};

assertions_clause {-> machine_clause} = assertions [predicates]:assertions_pred_list {-> New machine_clause.assertions([predicates.predicate])};

assertions_pred_list {-> predicate*} =
  {single} [predicate]:predicate_top {-> [predicate.predicate]} |
  {multi} [rest]:assertions_pred_list semicolon [predicate]:predicate_top {-> [rest.predicate, predicate.predicate]};

values_clause {-> machine_clause} = value [entries]:values_entries_list {-> New machine_clause.values([entries.values_entry])};

values_entries_list {-> values_entry*} =
  {single} [entry]:values_entry {-> [entry.values_entry]} |
  {multi} [rest]:values_entries_list semicolon [entry]:values_entry {-> [rest.values_entry, entry.values_entry]};

values_entry = [identifier]:composed_identifier equal [value]:expression_top_with_opt_desc
  // one could allow expression_or_id_list here w/o creating shift/reduce conflicts
     {-> New values_entry([identifier.identifier_literal], value.expression)};

local_operations_clause {-> machine_clause} = local_operations [operation_list]:operation_list {-> New machine_clause.local_operations([operation_list.operation])};

operations_clause {-> machine_clause} =
  operations [operation_list]:operation_list {-> New machine_clause.operations([operation_list.operation])} |
  {invalid_semicolon} operations [operation_list]:operation_list semicolon {-> New machine_clause.invalid_operations_clause(semicolon)};

operation_list {-> operation*} =
  {single} [operation]:operation {-> [operation.operation]} |
  {multi} [rest]:operation_list semicolon [operation]:operation {-> [rest.operation, operation.operation]} |
  {missing_semicolon} [rest]:operation_list [operation]:operation {-> [rest.operation, New operation.missing_semicolon(operation)]};

operation {-> operation} =
  {description} [operation]:operation [description]:description_pragma {-> New operation.description(description.description_pragma, operation)}
  // this allows description pragmas at the very end of an operation, not before the equal (=) sign
  |
  {normal_operation} [return_values]:operation_return_values? [op_name]:composed_identifier [parameters]:op_params? equal [operation_body]:substitution_l2
    {-> New operation([return_values.expression], [op_name.identifier_literal], [parameters.expression], operation_body.substitution)}
    // Note: operation names can be composed identifiers within refinements, see section 7.23 in Atelier-B handbook
    // TODO: allow also to use description pragmas here
    |
  {refined_operation} [return_values]:operation_return_values? [op_name]:composed_identifier [parameters]:op_params? [ref]:identifier_literal [ab_op_name]:identifier_literal equal [operation_body]:substitution_l2
    {-> New operation.refined([return_values.expression], [op_name.identifier_literal], [parameters.expression], ref, ab_op_name , operation_body.substitution)}
    // this supports the ref keyword for Event-B style refinement
    |
  {rule_operation} kw_rule [rule_name]:identifier_literal [attributes]:operation_attribute_list? kw_body [operation_body]:substitution_l0 end
    {-> New operation.rule(rule_name, [attributes.operation_attribute], operation_body.substitution)} |
  {computation} kw_computation [name]:identifier_literal [attributes]:operation_attribute_list? kw_body [body]:substitution_l0 end
    {-> New operation.computation(name, [attributes.operation_attribute], body.substitution)}
     |
  {function} kw_function [return_values]:operation_return_values [name]:identifier_literal [parameters]:op_params? [attributes]:operation_attribute_list? kw_body [body]:substitution_l0 end
    {-> New operation.function([return_values.expression], name, [parameters.expression], [attributes.operation_attribute], body.substitution)};

operation_attribute_list {-> operation_attribute*} =
  {single} [attr]:operation_attribute {-> [attr.operation_attribute]} |
  {multi} [rest]:operation_attribute_list [attr]:operation_attribute {-> [rest.operation_attribute, attr]};

operation_attribute {-> operation_attribute} =
  {attribute} [name]:kw_attribute_identifier [arguments]:expression_list {-> New operation_attribute(name, [arguments.expression])} |
  {predicate_attribute} [name]:kw_predicate_attribute [predicate]:predicate_top {-> New operation_attribute.predicate_attribute(name, predicate.predicate)};

operation_return_values {-> expression*} =
  [return_values]:identifier_declaration_list output_parameters {-> [return_values.expression]};

freetypes_clause {-> machine_clause} = kw_freetypes [freetype_list]:freetype_list {-> New machine_clause.freetypes([freetype_list.freetype])};
freetype_list {-> freetype*} =
  {single} [freetype]:freetype {-> [freetype.freetype]} |
  {multi} [rest]:freetype_list semicolon [freetype]:freetype {-> [rest.freetype, freetype.freetype]} ;
freetype {-> freetype} = [name]:identifier_literal [parameters]:def_parameters? equal [cons_list]:freetypecons_list
  {-> New freetype(name, [parameters.expression], [cons_list.freetype_constructor])};
freetypecons_list {-> freetype_constructor*} =
  {single} [constructor]:freetypecons {-> [constructor.freetype_constructor]} |
  {multi} [rest]:freetypecons_list comma [constructor]:freetypecons {-> [rest.freetype_constructor, constructor.freetype_constructor]};

freetypecons {-> freetype_constructor} =
  {element} [name]:identifier_literal {-> New freetype_constructor.element(name)} |
  {constructor} [name]:identifier_literal left_par [argument]:expression_in_par right_par {-> New freetype_constructor.constructor(name, argument.expression)};

/* Predicates */
predicate_top {-> predicate} = [pred]:predicate_p30 {-> pred.predicate};

predicate_p30 {-> predicate} =
  {implication} [left]:predicate_p30 implies [right]:predicate_p40 {-> New predicate.implication(left.predicate, right.predicate)} | // rechtsassoziativ?
  {next_level} [pred]:predicate_p40 {-> pred.predicate};

predicate_p40 {-> predicate} =
  {disjunct} [left]:predicate_p40 logical_or [right]:predicate_x40 {-> New predicate.disjunct(left.predicate, right.predicate)} |
  {conjunct} [left]:predicate_p40 conjunction [right]:predicate_x40 {-> New predicate.conjunct(left.predicate, right.predicate)} |
  {next_level} [pred]:predicate_x40 {-> pred.predicate};

predicate_x40 {-> predicate} =
  {label} pragma_label [name]:pragma_id_or_string pragma_end [predicate]:predicate_x40 {-> New predicate.label(name,predicate.predicate)} |
  {next_level} [pred]:predicate_x41 {-> pred.predicate};

predicate_x41 {-> predicate} =
  {description} [predicate]:predicate_p60 [description]:description_pragma
      {-> New predicate.description(description.description_pragma, predicate.predicate)} |
  {next_level} [pred]:predicate_x42
      {-> pred.predicate};
predicate_x42 {-> predicate} = [pred]:predicate_p60 {-> pred.predicate};

predicate_p60 {-> predicate} =
  {equivalence} [left]:predicate_p60 equivalence [right]:predicate_x60 {-> New predicate.equivalence(left.predicate, right.predicate)} |
  {next_level} [pred]:predicate_x60 {-> pred.predicate};
predicate_x60 {-> predicate} = [pred]:predicate_atomic {-> pred.predicate};

/* The predicates of the following levels have completely moved down to the atomic level:
predicate_p110 {-> predicate} =
  {next_level} [pred]:predicate_x110 {-> pred.predicate};
predicate_x110 {-> predicate} = [pred]:predicate_p160 {-> pred.predicate};

predicate_p160 {-> predicate} =
  {next_level} [pred]:predicate_x160 {-> pred.predicate};
predicate_x160 {-> predicate} = [pred]:predicate_atomic {-> pred.predicate};
*/

predicate_atomic {-> predicate} =
  // lhs_expression should really be assign_list and not expression_list,
  // but that causes reduce/reduce conflicts with sequence extensions.
  {subst} left_bracket [lhs_expression]:expression_list assign [rhs_expressions]:expression_list right_bracket [pred]:predicate_atomic
    {-> New predicate.substitution(New substitution.assign([lhs_expression.expression], [rhs_expressions.expression]), pred.predicate) } | //weakest precondition
    /* The following predicates have a priority in the AtelierB manual.
       But we (in contrast to AtelierB) distinguish between predicates and expression and
       can put the predicates of the form EXPR*EXPR -> PRED here.
       Thus fewer parenthesis can be used */
    /* Original priority: 60 */
  {equal} [left]:expression_top equal [right]:expression_top {-> New predicate.equal(left.expression, right.expression)} |
  {member} [left]:expression_top element_of [right]:expression_top {-> New predicate.member(left.expression, right.expression)} |
    /* Original priority: 110 */
  {subset} [left]:expression_top inclusion[right]:expression_top {-> New predicate.subset(left.expression, right.expression)} |
  {subset_strict} [left]:expression_top strict_inclusion [right]:expression_top {-> New predicate.subset_strict(left.expression, right.expression)} |
  {not_subset} [left]:expression_top non_inclusion [right]:expression_top {-> New predicate.not_subset(left.expression, right.expression)} |
  {not_subset_strict} [left]:expression_top strict_non_inclusion [right]:expression_top {-> New predicate.not_subset_strict(left.expression, right.expression)} |
  {superset} [left]:expression_top superset[right]:expression_top {-> New predicate.subset(right.expression, left.expression)} | // reverse arguments
  {superset_strict} [left]:expression_top superset_strict[right]:expression_top {-> New predicate.subset_strict(right.expression, left.expression)} | // reverse arguments
  {not_superset_strict} [left]:expression_top not_superset_strict[right]:expression_top {-> New predicate.not_subset_strict(right.expression, left.expression)} | // reverse arguments
  {not_superset} [left]:expression_top not_superset[right]:expression_top {-> New predicate.not_subset(right.expression, left.expression)} | // reverse arguments
  {contains_element} [left]:expression_top contains_element [right]:expression_top {-> New predicate.member(right.expression, left.expression)} | // reverse arguments
    /* Original priority: 160 */
  {not_equal} [left]:expression_top not_equal [right]:expression_top {-> New predicate.not_equal(left.expression, right.expression)} |
  {not_member} [left]:expression_top not_belonging [right]:expression_top {-> New predicate.not_member(left.expression, right.expression)} |
  {not_contains_element} [left]:expression_top not_contains_element [right]:expression_top {-> New predicate.not_member(right.expression, left.expression)} | // reverse arguments
  {less_equal} [left]:expression_top less_equal [right]:expression_top {-> New predicate.less_equal(left.expression, right.expression)} |
  {less} [left]:expression_top less [right]:expression_top {-> New predicate.less(left.expression, right.expression)} |
  {greater_equal} [left]:expression_top greater_equal [right]:expression_top {-> New predicate.greater_equal(left.expression, right.expression)} |
  {greater} [left]:expression_top greater [right]:expression_top {-> New predicate.greater(left.expression, right.expression)} |

  /* Now we continue with the real atomic predicates: */
  {bfalse} bfalse {-> New predicate.falsity()} |
  {truth_predicate} truth_predicate {-> New predicate.truth()} |
  {bracketed} left_par [predicate]:predicate_top right_par {-> predicate.predicate} |
  {negation} not left_par [predicate]:predicate_top right_par {-> New predicate.negation(predicate.predicate)} |
  {finite} finite left_par [set]:expression_in_par right_par {-> New predicate.finite(set.expression)} |
  {partition} partition left_par [set]:expression_top [elements]:comma_expression_list? right_par {-> New predicate.partition(set.expression, [elements.expression])} |
  {forall} for_any [identifiers]:quantified_variables_list dot left_par [implication]:predicate_top right_par {-> New predicate.forall([identifiers.expression], implication.predicate)}
  | // check in typechecker: predicate must be an implication predicate
  {forall2} for_any [identifiers]:quantified_variables_list dot2 left_par [implication]:predicate_top right_par {-> New predicate.forall([identifiers.expression], implication.predicate)}
  | // version with alternate dot
  {exists} exists [identifiers]:quantified_variables_list dot left_par [predicate]:predicate_top right_par {-> New predicate.exists([identifiers.expression], predicate.predicate)}
  |
  {exists2} exists [identifiers]:quantified_variables_list dot2 left_par [predicate]:predicate_top right_par {-> New predicate.exists([identifiers.expression], predicate.predicate)}
  |
  {definition} [def_literal]:def_literal_predicate [parameters]:def_call_params? {-> New predicate.definition(def_literal, [parameters.expression])}
  |
  {if_predicate} if [condition]:predicate_top then [then_pred]:predicate_top [elsifs]:if_elseif_predicate* else [else_pred]:predicate_top end
    {-> New predicate.if_predicate(condition.predicate, then_pred.predicate, [elsifs.predicate], else_pred.predicate)} |
  {let_predicate} let [identifiers]:identifier_declaration_list be [definition]:predicate_top in [pred]:predicate_top end
    {-> New predicate.let_predicate([identifiers.expression], definition.predicate, pred.predicate)} |
  {predicate_operator} [name]:kw_predicate_operator [parameters]:op_params {-> New predicate.operator(name,[parameters.expression])}; // extension

if_elseif_predicate {-> predicate} =
  elsif [condition]:predicate_top then [pred]:predicate_top {-> New predicate.if_elsif_predicate(condition.predicate, pred.predicate)};

/* Expressions */

/* expression_in_par contains the priority level 20, it is not considered as expression_top
   because ; and || should only be used inside parentheses */
expression_in_par {-> expression} =
  {description} [expression]:expression_in_par2 [description]:description_pragma
        /* we allow descriptions for expressions in parentheses; no ambiguity possible */
      {-> New expression.description(description.description_pragma, expression.expression)} |
  {next_level} [expr]:expression_in_par2
     {-> expr.expression};

/* expressions inside (.) allowing ; and || operators */
expression_in_par2 {-> expression} =
  {composition} [left]:expression_in_par semicolon [right]:expression_top
     {-> New expression.composition(left.expression, right.expression)} |
  {symbolic_composition} [left]:expression_in_par pragma_symbolic pragma_end semicolon [right]:expression_top
     {-> New expression.symbolic_composition(left.expression, right.expression)} |
  {parallel_product} [left]:expression_in_par double_vertical_bar [right]:expression_top
     {-> New expression.parallel_product(left.expression, right.expression)} |
  {next_level} [expr]:expression_top_with_opt_desc // using expression_or_id_list here leads to shit/reduce conflict
        /* we allow descriptions for expressions inside parentheses, no ambiguity with predicates possible */
     {-> expr.expression};

/* expressions top, with optional desc pragma, but without ; and || */
expression_top_with_opt_desc {-> expression} =
  {description} [expression]:expression_top [description]:description_pragma
        /* we allow descriptions for expressions, can be used when no ambiguity (e.g., with predicate desc) possible */
      {-> New expression.description(description.description_pragma, expression.expression)} |
  {next_level} [expr]:expression_p125
     {-> expr.expression};

/* expressions top,  without ; and || */
expression_top {-> expression} = [expr]:expression_p125 {-> expr.expression};

/*expression_p20 {-> expression} =
  {parallel_product} left_par [left]:expression_p20 double_vertical_bar [right]:expression_x20 right_par {-> New expression.parallel_product(left.expression, right.expression)} | // zu sehr eingeschraenkt?!?
  {next_level} [expr]:expression_x20 {-> expr.expression};
expression_x20 {-> expression} = [expr]:expression_p125 {-> expr.expression}; */

// Priority 125:
expression_p125 {-> expression} =
  {relations} [left]:expression_p125 set_relation [right]:expression_p160 {-> New expression.relations(left.expression, right.expression)} |
  {partial_function} [left]:expression_p125 partial_function [right]:expression_p160 {-> New expression.partial_function(left.expression, right.expression)} |
  {total_function} [left]:expression_p125 total_function [right]:expression_p160 {-> New expression.total_function(left.expression, right.expression)} |
  {partial_injection} [left]:expression_p125 partial_injection [right]:expression_p160 {-> New expression.partial_injection(left.expression, right.expression)} |
  {total_injection} [left]:expression_p125 total_injection [right]:expression_p160 {-> New expression.total_injection(left.expression, right.expression)} |
  {partial_surjection} [left]:expression_p125 partial_surjection [right]:expression_p160 {-> New expression.partial_surjection(left.expression, right.expression)} |
  {total_surjection} [left]:expression_p125 total_surjection [right]:expression_p160 {-> New expression.total_surjection(left.expression, right.expression)} |
  {partial_bijection} [left]:expression_p125 partial_bijection [right]:expression_p160 {-> New expression.partial_bijection(left.expression, right.expression)} |
  {total_bijection} [left]:expression_p125 total_bijection [right]:expression_p160 {-> New expression.total_bijection(left.expression, right.expression)} |
  {total_relation} [left]:expression_p125 total_relation [right]:expression_p160 {-> New expression.total_relation(left.expression, right.expression)} |
  {surjection_relation} [left]:expression_p125 surjection_relation [right]:expression_p160 {-> New expression.surjection_relation(left.expression, right.expression)} |
  {total_surjection_relation} [left]:expression_p125 total_surjection_relation [right]:expression_p160 {-> New expression.total_surjection_relation(left.expression, right.expression)} |
  {next_level} [expr]:expression_p160 {-> expr.expression};

// Priority 160:
expression_p160 {-> expression} =
  {overwrite} [left]:expression_p160 overwrite_relation [right]:expression_p170 {-> New expression.overwrite(left.expression, right.expression)} |
  {direct_product} [left]:expression_p160 direct_product [right]:expression_p170 {-> New expression.direct_product(left.expression, right.expression)} |
  {ring} [left]:expression_p160 ring [right]:expression_p170 {-> New expression.ring(left.expression, right.expression)} |
  {concat} [left]:expression_p160 concat_sequence [right]:expression_p170 {-> New expression.concat(left.expression, right.expression)} |
  {domain_restriction} [left]:expression_p160 domain_restriction [right]:expression_p170 {-> New expression.domain_restriction(left.expression, right.expression)} |
  {domain_subtraction} [left]:expression_p160 domain_subtraction [right]:expression_p170 {-> New expression.domain_subtraction(left.expression, right.expression)} |
  {range_restriction} [left]:expression_p160 range_restriction [right]:expression_p170 {-> New expression.range_restriction(left.expression, right.expression)} |
  {range_subtraction} [left]:expression_p160 range_subtraction [right]:expression_p170 {-> New expression.range_subtraction(left.expression, right.expression)} |
  {insert_front} [left]:expression_p160 insert_start_sequence [right]:expression_p170 {-> New expression.insert_front(left.expression, right.expression)} |
  {insert_tail} [left]:expression_p160 insert_end_sequence [right]:expression_p170 {-> New expression.insert_tail(left.expression, right.expression)} |
  {union} [left]:expression_p160 union [right]:expression_p170 {-> New expression.union(left.expression, right.expression)} |
  {intersection} [left]:expression_p160 intersection [right]:expression_p170 {-> New expression.intersection(left.expression, right.expression)} |
  {restrict_front} [left]:expression_p160 restrict_head_sequence [right]:expression_p170 {-> New expression.restrict_front(left.expression, right.expression)} |
  {restrict_tail} [left]:expression_p160 restrict_tail_sequence [right]:expression_p170 {-> New expression.restrict_tail(left.expression, right.expression)} |
  {couple1} [left]:expression_p160 maplet [right]:expression_p170 {-> New expression.couple([left.expression, right.expression])} |
  {next_level} [expr]:expression_p170 {-> expr.expression};

// Priority 170:
expression_p170 {-> expression} =
  {interval} [left_border]:expression_p170 interval [right_border]:expression_p180 {-> New expression.interval(left_border.expression, right_border.expression)} |
  {next_level} [expr]:expression_p180 {-> expr.expression};

// Priority 180:
expression_p180 {-> expression} =
  {minus_or_set_subtract} [left]:expression_p180 minus [right]:expression_p190 {-> New expression.minus_or_set_subtract(left.expression, right.expression)} |
  {add} [left]:expression_p180 plus [right]:expression_p190 {-> New expression.add(left.expression, right.expression)} |
  {set_subtraction} [left]:expression_p180 set_subtraction [right]:expression_p190 {-> New expression.set_subtraction(left.expression, right.expression)} |
  {next_level} [expr]:expression_p190 {-> expr.expression};

// Priority 190:
expression_p190 {-> expression} =
  {mul} [left]:expression_p190 product [right]:expression_p200 {-> New expression.mult_or_cart(left.expression, right.expression)} |
  {mulcart} [left]:expression_p190 cartesian_product [right]:expression_p200 {-> New expression.cartesian_product(left.expression, right.expression)} |
  {div} [left]:expression_p190 division [right]:expression_p200 {-> New expression.div(left.expression, right.expression)} |
  {modulo} [left]:expression_p190 mod [right]:expression_p200 {-> New expression.modulo(left.expression, right.expression)} |
  {next_level} [expr]:expression_p200 {-> expr.expression};

// Priority 200:
/* Attention: power_of is right-assoziative! */
expression_p200 {-> expression} =
  {power_of} [left]:expression_x200 power_of [right]:expression_p200 {-> New expression.power_of(left.expression, right.expression)} | // right associative!
  {next_level} [expr]:expression_x200 {-> expr.expression};

// Priority 201: CHECK IF Correct place for oftype
expression_x200 {-> expression} =
  {typeof} [left]:expression_p210 oftype [right]:expression_p210 {-> New expression.typeof(left.expression, right.expression)} | // TODO: check priority and nesting that should be allowed
  [expr]:expression_p210 {-> expr.expression};

// Priority 210:
expression_p210 {-> expression} =
  {unary_minus} minus [expression]:expression_p230 {-> New expression.unary_minus(expression.expression)} |
  {next_level} [expr]:expression_p230 {-> expr.expression};

// Priority 230:
expression_p230 {-> expression} =
  {reverse} [expression]:expression_p231 tilde {-> New expression.reverse(expression.expression)} |
  {next_level} [expr]:expression_p231 {-> expr.expression};

// Priority 231:
expression_p231 {-> expression} =
  {image} [left]:expression_p230 left_bracket [right]:expression_in_par right_bracket {-> New expression.image(left.expression, right.expression)} |
  {next_level} [expr]:expression_keyword {-> expr.expression};

expression_keyword {-> expression} =
  {convert_bool} bool_cast left_par [predicate]:predicate_top right_par {-> New expression.convert_bool(predicate.predicate)} |
  {max} max left_par [expression]:expression_in_par right_par {-> New expression.max(expression.expression)} |
  {min} min left_par [expression]:expression_in_par right_par {-> New expression.min(expression.expression)} |
  {card} card left_par [expression]:expression_in_par right_par {-> New expression.card(expression.expression)} |
  {convert_int_floor} convert_int_floor left_par [expression]:expression_in_par right_par {-> New expression.convert_int_floor(expression.expression)} |
  {convert_int_ceiling} convert_int_ceiling left_par [expression]:expression_in_par right_par {-> New expression.convert_int_ceiling(expression.expression)} |
  {convert_real} convert_real left_par [expression]:expression_in_par right_par {-> New expression.convert_real(expression.expression)}
  |
  {general_sum} sigma [identifiers]:quantified_variables_list dot left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.general_sum([identifiers.expression], predicates.predicate, expression.expression)} |
  {general_sum2} sigma [identifiers]:quantified_variables_list dot2 left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.general_sum([identifiers.expression], predicates.predicate, expression.expression)} |
  {general_product} pi [identifiers]:quantified_variables_list dot left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.general_product([identifiers.expression], predicates.predicate, expression.expression)} |
  {general_product2} pi [identifiers]:quantified_variables_list dot2 left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.general_product([identifiers.expression], predicates.predicate, expression.expression)}
  |
  {pow_subset} pow left_par [expression]:expression_in_par right_par {-> New expression.pow_subset(expression.expression)} |
  {pow1_subset} pow1 left_par [expression]:expression_in_par right_par {-> New expression.pow1_subset(expression.expression)} |
  {fin_subset} fin left_par [expression]:expression_in_par right_par {-> New expression.fin_subset(expression.expression)} |
  {fin1_subset} fin1 left_par [expression]:expression_in_par right_par {-> New expression.fin1_subset(expression.expression)} |
  {general_union} generalized_union left_par [expression]:expression_in_par right_par {-> New expression.general_union(expression.expression)} |
  {general_intersection} generalized_inter left_par [expression]:expression_in_par right_par {-> New expression.general_intersection(expression.expression)} |
  {identity} id left_par [expression]:expression_in_par right_par {-> New expression.identity(expression.expression)} |
  {reflexive_closure} closure left_par [expression]:expression_in_par right_par {-> New expression.reflexive_closure(expression.expression)} |
  {closure} closure1 left_par [expression]:expression_in_par right_par {-> New expression.closure(expression.expression)}
  |
  {domain} dom left_par [expression]:expression_in_par right_par {-> New expression.domain(expression.expression)} |
  {range} ran left_par [expression]:expression_in_par right_par {-> New expression.range(expression.expression)}
  |
  {lambda} lambda [identifiers]:quantified_variables_list dot left_par [predicate]:predicate_top vertical_bar [expression]:expression_in_par right_par
    {-> New expression.lambda([identifiers.expression], predicate.predicate, expression.expression)} |
  {lambda2} lambda [identifiers]:quantified_variables_list dot2 left_par [predicate]:predicate_top vertical_bar [expression]:expression_in_par right_par
    {-> New expression.lambda([identifiers.expression], predicate.predicate, expression.expression)}
  |
  {symbolic_lambda} pragma_symbolic pragma_end lambda [identifiers]:quantified_variables_list dot left_par [predicate]:predicate_top vertical_bar [expression]:expression_in_par right_par
    {-> New expression.symbolic_lambda([identifiers.expression], predicate.predicate, expression.expression)} |
  {symbolic_lambda2} pragma_symbolic pragma_end lambda [identifiers]:quantified_variables_list dot2 left_par [predicate]:predicate_top vertical_bar [expression]:expression_in_par right_par
    {-> New expression.symbolic_lambda([identifiers.expression], predicate.predicate, expression.expression)}
  |
  {trans_function} fnc left_par [expression]:expression_in_par right_par {-> New expression.trans_function(expression.expression)} |
  {trans_relation} rel left_par [expression]:expression_in_par right_par {-> New expression.trans_relation(expression.expression)}
  |
  {seq} seq left_par [expression]:expression_in_par right_par {-> New expression.seq(expression.expression)} |
  {seq1} seq1 left_par [expression]:expression_in_par right_par {-> New expression.seq1(expression.expression)} |
  {iseq} iseq left_par [expression]:expression_in_par right_par {-> New expression.iseq(expression.expression)} |
  {iseq1} iseq1 left_par [expression]:expression_in_par right_par {-> New expression.iseq1(expression.expression)} |
  {perm} perm left_par [expression]:expression_in_par right_par {-> New expression.perm(expression.expression)} |
  {empty_sequence1} left_bracket right_bracket {-> New expression.empty_sequence()} |
  {empty_sequence2} less_greater {-> New expression.empty_sequence()} | // not allowed by Atelier-B
  {size} size left_par [expression]:expression_in_par right_par {-> New expression.size(expression.expression)} |
  {first} first left_par [expression]:expression_in_par right_par {-> New expression.first(expression.expression)} |
  {last} last left_par [expression]:expression_in_par right_par {-> New expression.last(expression.expression)} |
  {front} front left_par [expression]:expression_in_par right_par {-> New expression.front(expression.expression)} |
  {tail} tail left_par [expression]:expression_in_par right_par {-> New expression.tail(expression.expression)} |
  {rev} rev left_par [expression]:expression_in_par right_par {-> New expression.rev(expression.expression)}
  |
  {first_projection} prj1 left_par [exp1]:expression_in_par comma [exp2]:expression_in_par right_par {-> New expression.first_projection(exp1.expression, exp2.expression)} |
  {second_projection} prj2 left_par [exp1]:expression_in_par comma [exp2]:expression_in_par right_par {-> New expression.second_projection(exp1.expression, exp2.expression)}
  | // now prj1/prj2 without typing arguments, e.g., prj1(1|->2) = 1
  {first_projection_no_types} prj1 left_par [exp1]:expression_in_par right_par {-> New expression.function( New expression.event_b_first_projection_v2(), [exp1.expression])} |
  {second_projection_no_types} prj2 left_par [exp1]:expression_in_par right_par {-> New expression.function( New expression.event_b_second_projection_v2(), [exp1.expression])}
  | // prj1/prj2 fully without parameters such as in @prj1[{1|->2}]
  {event_b_first_projection} prj1_v2 {-> New expression.event_b_first_projection_v2()} |
  {event_b_second_projection} prj2_v2 {-> New expression.event_b_second_projection_v2()}
  |
  {iteration} iterate left_par [left]:expression_in_par comma [right]:expression_in_par right_par {-> New expression.iteration(left.expression, right.expression)}
  |
  // The identifier lists in all comprehension sets should really be quantified_variables_list and not expression_list(_in_par),
  // but that causes reduce/reduce conflicts with set extensions (literals).
  // Instead, IdentListCheck later enforces that only identifiers are used.
  {comprehension_set} left_brace [identifiers]:expression_list_in_par vertical_bar [predicates]:predicate_top right_brace {-> New expression.comprehension_set([identifiers.expression], predicates.predicate)} |
  {symbolic_comprehension_set} pragma_symbolic pragma_end left_brace [identifiers]:expression_list_in_par vertical_bar [predicates]:predicate_top right_brace {-> New expression.symbolic_comprehension_set([identifiers.expression], predicates.predicate)}
  |
  // because of possible conflicts this requires parentheses around identifiers when using the dot as a separator!
  {event_b_comprehension_set} left_brace [identifiers]:comprehension_set_identifiers_with_parentheses dot [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_brace
   {-> New expression.event_b_comprehension_set([identifiers.expression], expression.expression, predicates.predicate)} |
  {symbolic_event_b_comprehension_set}  pragma_symbolic pragma_end left_brace [identifiers]:comprehension_set_identifiers_with_parentheses dot [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_brace
   {-> New expression.symbolic_event_b_comprehension_set([identifiers.expression], expression.expression, predicates.predicate)} |
  {event_b_comprehension_set2} left_brace [identifiers]:expression_list_in_par dot2 [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_brace
    {-> New expression.event_b_comprehension_set([identifiers.expression], expression.expression, predicates.predicate)} |
  {symbolic_event_b_comprehension_set2} pragma_symbolic pragma_end left_brace [identifiers]:expression_list_in_par dot2 [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_brace
    {-> New expression.symbolic_event_b_comprehension_set([identifiers.expression], expression.expression, predicates.predicate)}
  |
  {quantified_union} quantified_union [identifiers]:quantified_variables_list dot left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.quantified_union([identifiers.expression], predicates.predicate, expression.expression)} |
  {quantified_union2} quantified_union [identifiers]:quantified_variables_list dot2 left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.quantified_union([identifiers.expression], predicates.predicate, expression.expression)} |
  {symbolic_quantified_union} pragma_symbolic pragma_end quantified_union [identifiers]:quantified_variables_list dot left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.symbolic_quantified_union([identifiers.expression], predicates.predicate, expression.expression)} |
  {symbolic_quantified_union2} pragma_symbolic pragma_end quantified_union [identifiers]:quantified_variables_list dot2 left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.symbolic_quantified_union([identifiers.expression], predicates.predicate, expression.expression)}
  |
  {quantified_intersection} quantified_inter [identifiers]:quantified_variables_list dot left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.quantified_intersection([identifiers.expression], predicates.predicate, expression.expression)} |
  {quantified_intersection2} quantified_inter [identifiers]:quantified_variables_list dot2 left_par [predicates]:predicate_top vertical_bar [expression]:expression_in_par right_par {-> New expression.quantified_intersection([identifiers.expression], predicates.predicate, expression.expression)}
  |
  {set_extension} left_brace [expressions]:expression_list_in_par right_brace {-> New expression.set_extension([expressions.expression])} |
  {sequence_extension} left_bracket [expressions]:expression_list right_bracket {-> New expression.sequence_extension([expressions.expression])} |
  {couple2} [expression]:couple2 {-> expression.expression} |
  {general_concat} conc left_par [expression]:expression_in_par right_par {-> New expression.general_concat(expression.expression)} |
  {struct} struct left_par [entries]:rec_entry_list right_par {-> New expression.struct([entries.rec_entry])} |
  {rec} rec left_par [entries]:rec_entry_list right_par {-> New expression.rec([entries.rec_entry])} |
  {record_field} [record]:expression_p231 single_quotation [identifier]:identifier_literal {-> New expression.record_field(record.expression, identifier)} |
  {expression_operator} [name]:kw_expression_operator [parameters]:op_params {-> New expression.operator(name, [parameters.expression])} | // extension
  {next_level} [expr]:expression_func {-> expr.expression};

rec_entry {-> rec_entry} =
  {in_pars} left_par [identifier]:identifier_literal element_of [value]:expression_in_par right_par {-> New rec_entry(identifier, value.expression)} |
  {no_pars} [identifier]:identifier_literal element_of [value]:expression_in_par {-> New rec_entry(identifier, value.expression)};

rec_entry_list {-> rec_entry*} =
  {single} [entry]:rec_entry {-> [entry.rec_entry]} |
  {multi} [rest]:rec_entry_list comma [last]:rec_entry {-> [rest.rec_entry, last.rec_entry]};

expression_func {-> expression} =
  {function} [function]:expression_p230 left_par [parameters]:expression_list right_par {-> New expression.function(function.expression, [parameters.expression])} |
  {next_level} expression_atomic {-> expression_atomic.expression};

expression_atomic {-> expression} =
  {paren} left_par [expression]:expression_in_par right_par {-> expression.expression} |
  {identifier} [identifier]:composed_identifier {-> New expression.identifier([identifier.identifier_literal])} |
  {primed_identifier} [identifier]:composed_identifier b_prime {-> New expression.primed_identifier([identifier.identifier_literal])} |
  {string} [content]:string_literal {-> New expression.string(content)} |
  {multiline_string} multiline_string_start [content]:multiline_string_content multiline_string_end {-> New expression.multiline_string(content)} |
  {multiline_template} multiline_template_start [content]:multiline_template_content multiline_template_end {-> New expression.multiline_template(content)} |
  {boolean_true} true {-> New expression.boolean_true()} |
  {boolean_false} false {-> New expression.boolean_false()} |
  {successor} succ {-> New expression.successor()} |
  {predecessor} pred {-> New expression.predecessor()} |
  {integer} [literal]:integer_literal {-> New expression.integer(literal)} |
  {real} [literal]:real_literal {-> New expression.real(literal)} |
  {hex_integer} [literal]:hex_literal {-> New expression.hex_integer(literal)} |
  {max_int} max_int {-> New expression.max_int()} |
  {min_int} min_int {-> New expression.min_int()} |
  {empty_set_symbol} empty_set {-> New expression.empty_set()} |
  {empty_set} left_brace right_brace {-> New expression.empty_set()} |
  {integer_set} integer {-> New expression.integer_set()} |
  {real_set} real {-> New expression.real_set()} |
  {float_set} float {-> New expression.float_set()} |
  {natural_set} natural {-> New expression.natural_set()} |
  {natural1_set} natural1 {-> New expression.natural1_set()} |
  {nat_set} nat {-> New expression.nat_set()} |
  {nat1_set} nat1 {-> New expression.nat1_set()} |
  {int_set} int {-> New expression.int_set()} |
  {bool_set} bool {-> New expression.bool_set()} |
  {if_expression} if [condition]:predicate_top then [then_expr]:expression_top_with_opt_desc [elsifs]:if_elseif_expression* else [else_expr]:expression_top_with_opt_desc end
     // Note: one could allow expression_or_id_list here w/o creating shift/reduce conflicts
    {-> New expression.if_then_else(condition.predicate, then_expr.expression, [elsifs.expression], else_expr.expression)} |
  {let_expression} let [identifiers]:identifier_declaration_list be [definition]:predicate_top in [expr]:expression_top_with_opt_desc end
    {-> New expression.let_expression([identifiers.expression], definition.predicate, expr.expression)} |
  {string_set} string {-> New expression.string_set()};

if_elseif_expression {-> expression} =
  elsif [condition]:predicate_top then [expr]:expression_top_with_opt_desc {-> New expression.if_elsif_expr(condition.predicate, expr.expression)};

expression_list {-> expression*} =
  [first]:expression_top [rest]:expression_list_tail* {-> [first.expression, rest.expression]};

expression_list_tail {-> expression} =
  comma [expr]:expression_top {-> expr.expression};

// used for partition(First[, Rest])
comma_expression_list {-> expression*} =
  comma expression_list {-> [expression_list.expression]};

expression_list_in_par {-> expression*} =
  [first]:expression_in_par [rest]:expression_list_in_par_tail* {-> [first.expression, rest.expression]};

expression_list_in_par_tail {-> expression} =
  comma [expr]:expression_in_par {-> expr.expression};

couple2 {-> expression} =
  left_par [first]:expression_in_par comma [rest]:expression_list_in_par right_par {-> New expression.couple([first.expression, rest.expression])}; // Klammern notwendig

comprehension_set_identifiers_with_parentheses {-> expression*} =
  {single} left_par [identifier]:expression_in_par right_par {-> [identifier.expression]} |
  {multi} [identifiers]:couple2 {-> [identifiers.expression]}; // will be unpacked by CoupleToIdentifierTransformation


/* Substitutions */

substitution_l0 {-> substitution} =
  {invalid} substitution_l2 semicolon {-> New substitution.invalid(semicolon)} |
  {next_level} substitution_l1 {-> substitution_l1.substitution};

substitution_l1 {-> substitution} =
  {sequence} [first]:substitution_l2 semicolon [second]:substitution_l2 [rest]:sequence_subst_tail? {-> New substitution.sequence([first.substitution, second.substitution, rest.substitution])} |
  {next_level} [sub]:substitution_l2 {-> sub.substitution};

sequence_subst_tail {-> substitution*} =
  {single} semicolon [substitution]:substitution_l2 {-> [substitution.substitution]} |
  {multi} semicolon [substitution]:substitution_l2 [rest]:sequence_subst_tail {-> [substitution.substitution, rest.substitution]} |
  {invalid} semicolon {-> [New substitution.invalid(semicolon)]};

substitution_l2 {-> substitution} =
  {parallel} [first]:substitution_l3 double_vertical_bar [second]:substitution_l3 [rest]:parallel_subst_tail? {-> New substitution.parallel([first.substitution, second.substitution, rest.substitution])} |
  {next_level} [sub]:substitution_l3 {-> sub.substitution};

parallel_subst_tail {-> substitution*} =
  {single} double_vertical_bar [substitution]:substitution_l3 {-> [substitution.substitution]} |
  {multi} double_vertical_bar [substitution]:substitution_l3 [rest]:parallel_subst_tail {-> [substitution.substitution, rest.substitution]};

substitution_l3 {-> substitution} =
  {block} begin [substitution]:substitution_l0 end
           {-> New substitution.block(substitution.substitution)} |
  {skip} skip {-> New substitution.skip()} |
  {assign} [lhs_expression]:assign_list assign [rhs_expressions]:expression_list
           {-> New substitution.assign([lhs_expression.expression], [rhs_expressions.expression])} |
  {precondition} pre [predicate]:predicate_top then [substitution]:substitution_l0 end
           {-> New substitution.precondition(predicate.predicate, substitution.substitution)} |
  {assertion} assert [predicate]:predicate_top then [substitution]:substitution_l0 end
           {-> New substitution.assertion(predicate.predicate, substitution.substitution)} |
  {witness_then} witness_kw [predicate]:predicate_top then [substitution]:substitution_l0 end
           {-> New substitution.witness_then(predicate.predicate, substitution.substitution)} |
  {choice} choice [first]:substitution_l0 [rest]:choice_or* end
           {-> New substitution.choice([first.substitution, rest.substitution])} |
  {if} if [condition]:predicate_top then [then_subst]:substitution_l0 [elsifs]:if_elsif* [else]:if_else? end
           {-> New substitution.if(condition.predicate, then_subst.substitution, [elsifs.substitution], else.substitution)} |
  {select} select [condition]:predicate_top then [then_subst]:substitution_l0 [whens]:select_when* [else]:select_else? end
           {-> New substitution.select(condition.predicate, then_subst.substitution, [whens.substitution], else.substitution)} |
  {case} case [case_expr]:expression_in_par of either [either_expr]:expression_list then [either_subst]:substitution_l0 [or_substitutions]:case_or* [else]:case_else? [end1]:end [end2]:end
           {-> New substitution.case(case_expr.expression, [either_expr.expression], either_subst.substitution, [or_substitutions.substitution], else.substitution)} |
  {any} any [identifiers]:identifier_declaration_list where [where_pred]:predicate_top then [then_subst]:substitution_l0 end
           {-> New substitution.any([identifiers.expression], where_pred.predicate, then_subst.substitution)} |
  // According to the Atelier-B reference manual,
  // the LHS of "becomes element of" and "becomes such that" substitutions can only contain (possibly dotted) identifiers.
  // assign_list allows a bit more than that (namely function calls and record fields),
  // but we cannot use a different production here,
  // because it would cause reduce/reduce conflicts with assignment substitutions.
  // Instead, IdentListCheck later enforces that only identifiers are used.
  // TODO Could/should we allow function calls and record fields here as an extension?
  {becomes_element_of} [identifiers]:assign_list double_colon [set]:expression_top
           {-> New substitution.becomes_element_of([identifiers.expression], set.expression)} |
  {becomes_such} [identifiers]:assign_list element_of left_par [predicate]:predicate_top right_par
           {-> New substitution.becomes_such([identifiers.expression], predicate.predicate)} |
  {var} var [identifiers]:identifier_declaration_list in [substitution]:substitution_l0 end
           {-> New substitution.var([identifiers.expression], substitution.substitution)} |

  // Ambiguous call: either an operation call without return values
  // or a definition call of a definition of type ExprOrSubst
  // (i. e. it was uncertain whether the RHS is an expression or a substitution).
  // In both cases, the call may have arguments (parsed as a function call expression)
  // or it may have no arguments (parsed as an identifier expression).
  // The OpSubstitutions visitor will transform the resulting operation_or_definition_call node
  // into an operation_call or definition substitution as appropriate.
  //
  // Definition calls of a definition of type Substitution
  // (i. e. the RHS is unambiguously a substitution)
  // are *not* handled by this alternative.
  // The PreParser transforms the definition call identifier into a def_literal_substitution token,
  // which will be handled by a different alternative that directly produces a definition substitution.
  //
  // Unrelated to this ambiguity, the call must be parsed as identifier_or_function_expression
  // to avoid shift/reduce conflicts with operation calls *with* return values:
  // without unlimited lookahead, it's impossible to tell whether "f(a,b,c,d,...)"
  // is part of a return value assignment ("f(a,b,c,d,...) <-- op(x,y,z)")
  // or an operation call ("f(a,b,c,d,...); skip").
  {operation_or_definition_call} [op]:identifier_or_function_expression
           {-> New substitution.operation_or_definition_call(op.expression)} | // check in semantic check if expression is a definition
  // Unambiguous call: the '<--' syntax for return values is only used for operation calls.
  // (Definition call substitutions cannot have return values.)
  {operation_call_with_return_values} [return_values]:assign_list output_parameters [op_name]:composed_identifier [parameters]:op_params?
           {-> New substitution.operation_call([return_values.expression], [op_name.identifier_literal], [parameters.expression])} |

  {while} while [condition]:predicate_top do [do_subst]:substitution_l0 invariant [invariant_pred]:predicate_top variant [variant_expr]:expression_in_par end
           {-> New substitution.while(condition.predicate, do_subst.substitution, invariant_pred.predicate, variant_expr.expression)} |
  {let} let [identifiers]:identifier_declaration_list be [predicate]:predicate_top in [substitution]:substitution_l0 end
           {-> New substitution.let([identifiers.expression], predicate.predicate, substitution.substitution)} |
  {definition} [def_literal]:def_literal_substitution [parameters]:def_call_params?
           {-> New substitution.definition(def_literal, [parameters.expression])} |

  // extensions for rules
  {for_loop} kw_for [identifiers]:identifier_declaration_list in [set]:expression_in_par do [do_subst]:substitution_l0 end
          {-> New substitution.for_loop([identifiers.expression], set.expression, do_subst.substitution)} |
  {forall_sub_message} kw_rule_for_all [identifiers]:identifier_declaration_list where [where_pred]:predicate_top
                       kw_expect [expect_pred]:predicate_top [error_type]:error_type?
                       [on_success]:on_success? kw_counterexample [message]:expression_top_with_opt_desc end
          {-> New substitution.forall_sub_message([identifiers.expression], where_pred.predicate, expect_pred.predicate, error_type.integer_literal, on_success.expression, message.expression)} |
  {rule_fail_sub} kw_rule_fail [identifiers]:identifier_declaration_list? [when_pred]:when_predicate?
                  [error_type]:error_type? kw_counterexample [message]:expression_top_with_opt_desc end
           {-> New substitution.rule_fail_sub([identifiers.expression], when_pred.predicate, error_type.integer_literal, message.expression)} |
  {substitution_operator} [name]:kw_substitution_operator [arguments]:op_params?
           {-> New substitution.operator(name, [arguments.expression])} |
  {define} kw_define [name]:identifier_literal kw_type [type]:expression_in_par
           [dummy]:dummy_value? kw_value [value]:expression_in_par end
           {-> New substitution.define(name, type.expression, dummy.expression, value.expression)};

when_predicate {-> predicate} = when [pred]:predicate_top {-> pred.predicate};
message {-> expression} = left_par [expr]:expression_in_par right_par {-> expr.expression};
dummy_value {-> expression} = kw_dummy_value [expr]:expression_in_par {-> expr.expression};
error_type {-> integer_literal} = kw_rule_error_type [id]:integer_literal {-> id};
on_success {-> expression} = kw_on_success [expr]:expression_top_with_opt_desc {-> expr.expression};

choice_or {-> substitution} =
  or [substitution]:substitution_l0 {-> New substitution.choice_or(substitution.substitution)};

if_elsif {-> substitution} =
  elsif [condition]:predicate_top then [subst]:substitution_l0 {-> New substitution.if_elsif(condition.predicate, subst.substitution)};

if_else {-> substitution} =
  else [subst]:substitution_l0 {-> subst.substitution};

select_when {-> substitution} =
  when [condition]:predicate_top then [subst]:substitution_l0 {-> New substitution.select_when(condition.predicate, subst.substitution)};

select_else {-> substitution} =
  else [subst]:substitution_l0 {-> subst.substitution};

case_or {-> substitution} =
  or [expressions]:expression_list then [subst]:substitution_l0 {-> New substitution.case_or([expressions.expression], subst.substitution)};

case_else {-> substitution} =
  else [subst]:substitution_l0 {-> subst.substitution};

op_params {-> expression*} =
  left_par [parameters]:expression_list right_par {-> [parameters.expression]};

/* Basics */
composed_identifier {-> identifier_literal*} =
  {single} [name]:identifier_literal {-> [name]} |
  {multi} [rest]:composed_identifier dot [first]:identifier_literal {-> [rest.identifier_literal, first]};
  // To do: maybe the only place where we do not want to also admit the second kind of dot '·' (generated by Rodin for quantifiers)

identifier_declaration_list {-> expression*} =
  {single} [identifier]:identifier_declaration {-> [identifier.expression]} |
  {multi} [rest]:identifier_declaration_list comma [identifier]:identifier_declaration {-> [rest.expression, identifier.expression]};

/* a,b,f(1),g(1)(2) := ... */
assign_list {-> expression*} =
  {single} [name]:assignment_target {-> [name.expression]} |
  {multi} [rest]:assign_list comma [name]:assignment_target {-> [rest.expression, name.expression]};

assignment_target {-> expression} =
  {record} [record]:assignment_target single_quotation [name]:identifier_literal {-> New expression.record_field(record.expression, name)} |
  {next_level} [expr]:identifier_or_function_expression {-> expr.expression};

identifier_or_function_expression {-> expression} =
  {identifier} [name]:composed_identifier {-> New expression.identifier([name.identifier_literal])} |
  {function} [name]:identifier_or_function_expression [parameters]:op_params {-> New expression.function(name.expression, [parameters.expression])};

quantified_variables_list {-> expression*} =
  {parentheses} left_par [id]:identifier_declaration_list right_par {-> [id.expression]} |
  {no_parentheses} [id]:identifier_declaration_list {-> [id.expression]};

identifier_declaration {-> expression} =
  {description} [identifier]:identifier_literal [description]:description_pragma {-> New expression.description(description.description_pragma, New expression.identifier([identifier]))} |
  {identifier} [identifier]:identifier_literal {-> New expression.identifier([identifier])};

def_call_params {-> expression*} = left_par [params]:expression_list right_par {-> [params.expression]};

/* Patterns for opertions */
operation_pattern {-> parse_unit }=
  [op_name]:composed_identifier [parameters]:op_pattern_params? {-> New parse_unit.oppattern([op_name.identifier_literal], [parameters.argpattern])};

op_pattern_params {-> argpattern*} =
  left_par [parameters]:oppattern_list right_par {-> [parameters.argpattern]} ;
oppattern_list {-> argpattern*} =
  {single} [arg]:op_pattern_param {-> [arg.argpattern]} |
  {multiple} [rest]:oppattern_list comma [last]:op_pattern_param {-> [rest.argpattern, last.argpattern]};
op_pattern_param {-> argpattern} =
  {def} [expression]:expression_in_par {-> New argpattern.def(expression.expression)} |
  {undef} underscore {-> New argpattern.undef()};

/*******************************************************************
 * Abstract Syntax Tree                                            *
 *******************************************************************/
Abstract Syntax Tree

parse_unit =
  {generated} parse_unit |
  {package} [package]:pragma_id_or_string [imports]:import_package* parse_unit |
  {abstract_machine} [variant]:machine_variant [header]:machine_header [machine_clauses]:machine_clause* |
  {refinement_machine} [header]:machine_header [ref_machine]:identifier_literal [machine_clauses]:machine_clause* |
  {implementation_machine} [header]:machine_header [ref_machine]:identifier_literal [machine_clauses]:machine_clause* |
  {definition_file} [definitions_clauses]:machine_clause |
  {predicate} predicate |
  {expression} expression |
  {substitution} substitution |
  {machine_clause} machine_clause |
  {event_b_context} [name]:identifier_literal [context_clauses]:context_clause* |
  {event_b_model} [name]:identifier_literal [model_clauses]:model_clause* |
  {oppattern} [name]:identifier_literal* [parameters]:argpattern* |
  {parse_unit_definition} definition;

import_package = [package]:pragma_id_or_string; // importing a package or machine using import pragma (e.g. /*@import-package "foo.bar" */ )

argpattern = {undef} | {def} expression;
/* csppattern = argtype argpattern; */
/* argtype = {join} | {in} | {out}; */

machine_variant = {machine} | {model} | {system};

machine_header =
  [name]:identifier_literal* [parameters]:expression*;

context_clause =
  {extends} [extends]:identifier_literal* |
  {sets} set* |
  {constants} [identifiers]:expression* |
  {abstract_constants} [identifiers]:expression* |
  {axioms} [predicates]:predicate* |
  {theorems} [predicates]:predicate*;

model_clause =
  {refines} [refines]:identifier_literal |
  {sees} [sees]:identifier_literal* |
  {variables} [identifiers]:expression* |
  {invariant} [predicates]:predicate* |
  {theorems} [predicates]:predicate* |
  {variant} [variant]:expression |
  {events} event*;

machine_clause =
  {definitions} [definitions]:definition* |
  {sees} [machine_names]:machine_reference_no_params* |
  {promotes} [operation_names]:operation_reference* |
  {uses} [machine_names]:machine_reference_no_params* |
  {includes} [machine_references]:machine_reference* |
  {extends} [machine_references]:machine_reference* |
  {imports} [machine_references]:machine_reference* |
  {sets} [set_definitions]:set* |
  {freetypes} [freetypes]:freetype* |
  {variables} [identifiers]:expression* |
  {concrete_variables} [identifiers]:expression* |
  {abstract_constants} [identifiers]:expression* |
  {constants} [identifiers]:expression* |
  {properties} [predicates]:predicate |
  {constraints} [predicates]:predicate |
  {initialisation} [substitutions]:substitution |
  {invariant} [predicates]:predicate |
  {assertions} [predicates]:predicate* |
  {values} [entries]:values_entry* |
  {local_operations} [operations]:operation* |
  {operations} [operations]:operation* |
  {references} [machine_references]:machine_reference* |
  {invalid_operations_clause} semicolon |
  {expressions} [expressions]:expression_definition* |
  {predicates} [predicates]:predicate_definition*;

machine_reference =
  [machine_name]:identifier_literal* [parameters]:expression* |
  {file} [reference]:machine_reference [file]:pragma_id_or_string;

machine_reference_no_params =
  [machine_name]:identifier_literal* |
  {file} [reference]:machine_reference_no_params [file]:pragma_id_or_string;

operation_reference = [operation_name]:identifier_literal*;

description_pragma = [parts]:pragma_free_text*;

expression_definition = [name]:identifier_literal [parameters]:expression* [rhs]:expression;
predicate_definition = [name]:identifier_literal [parameters]:expression* [rhs]:predicate;

definition =
  {predicate_definition} [name]:def_literal_predicate [parameters]:expression* [rhs]:predicate |
  {substitution_definition} [name]:def_literal_substitution [parameters]:expression* [rhs]:substitution |
  {expression_definition} [name]:identifier_literal [parameters]:expression* [rhs]:expression |
  {file_definition} [filename]:string_literal;

set =
  {description} [description]:description_pragma set |
  {deferred_set} [identifier]:identifier_literal* |
  {enumerated_set} [identifier]:identifier_literal* [elements]:expression* |
  {enumerated_set_via_def} [identifier]:identifier_literal* [elements_def]:identifier_literal*;  // covers:  SETS Id = ED; DEFINITIONS ED == {a,b,c}

freetype = [name]:identifier_literal  [parameters]:expression* [constructors]:freetype_constructor+;
freetype_constructor =
  {constructor} [name]:identifier_literal [argument]:expression |
  {element} [name]:identifier_literal;

values_entry = [identifier]:identifier_literal* [value]:expression;

operation =
  [return_values]:expression* [op_name]:identifier_literal* [parameters]:expression* [operation_body]:substitution |
  {missing_semicolon} operation |
  {description} [description]:description_pragma [operation]:operation |
  {refined} [return_values]:expression* [op_name]:identifier_literal* [parameters]:expression* [ref_kw]:identifier_literal [ab_op_name]:identifier_literal [operation_body]:substitution |
  {rule} [rule_name]:identifier_literal [attributes]:operation_attribute* [rule_body]:substitution |
  {computation} [name]:identifier_literal [attributes]:operation_attribute* [body]:substitution |
  {function} [return_values]:expression* [name]:identifier_literal [parameters]:expression* [attributes]:operation_attribute* [body]:substitution;

operation_attribute =
  [name]: kw_attribute_identifier [arguments]:expression* |
  {predicate_attribute} [name]:kw_predicate_attribute [predicate]:predicate;

event =
  [event_name]:identifier_literal [status]:eventstatus [refines]:identifier_literal*
    [variables]:expression* [guards]:predicate* [theorems]:predicate* [assignments]:substitution* [witness]:witness*
  |
  {description} [description]:description_pragma [event]:event;
witness = [name]:identifier_literal [predicate]:predicate;

eventstatus = {ordinary} | {anticipated} | {convergent};

/* Predicates */

predicate =
  {description} [description]:description_pragma [predicate]:predicate |
  {label} [name]:pragma_id_or_string [predicate]:predicate |
  {substitution} [substitution]:substitution [predicate]:predicate |
  {conjunct} [left]:predicate [right]:predicate |
  {negation} [predicate]:predicate |
  {disjunct} [left]:predicate [right]:predicate |
  {implication} [left]:predicate [right]:predicate |
  {equivalence} [left]:predicate [right]:predicate |
  {forall} [identifiers]:expression* [implication]:predicate |
  {exists} [identifiers]:expression* [predicate]:predicate |
  {equal} [left]:expression [right]:expression |
  {not_equal} [left]:expression [right]:expression |
  {member} [left]:expression [right]:expression |
  {not_member} [left]:expression [right]:expression |
  {subset} [left]:expression [right]:expression |
  {subset_strict} [left]:expression [right]:expression |
  {not_subset} [left]:expression [right]:expression |
  {not_subset_strict} [left]:expression [right]:expression |
  {less_equal} [left]:expression [right]:expression |
  {less} [left]:expression [right]:expression |
  {greater_equal} [left]:expression [right]:expression |
  {greater} [left]:expression [right]:expression |
  {truth} |
  {falsity} |
  {finite} [set]:expression |
  {partition} [set]:expression [elements]:expression* | /* Event-B only predicate */
  {definition} [def_literal]:def_literal_predicate [parameters]:expression* |
  {let_predicate} [identifiers]:expression* [assignment]:predicate [pred]:predicate |
  {if_elsif_predicate} [condition]:predicate [then]:predicate |
  {if_predicate} [condition]:predicate [then]:predicate [elsifs]:predicate* [else]:predicate |
  {extended_pred} [identifier]:identifier_literal [expressions]:expression* [predicates]:predicate* | /* Event-B only predicate - theory plugin */
  {operator} [name]:kw_predicate_operator [identifiers]:expression*; // extension for rules

/* Expressions */
expression =
  {description} [description]:description_pragma [expression]:expression |
  {identifier} [identifier]:identifier_literal* |
  {primed_identifier} [identifier]:identifier_literal* |
  {string} [content]:string_literal |
  {multiline_string} [content]:multiline_string_content |
  {multiline_template} [content]:multiline_template_content |
  {boolean_true} |
  {boolean_false} |
  {integer} [literal]:integer_literal |
  {real} [literal]:real_literal |
  {hex_integer} [literal]:hex_literal |
  {max_int} |
  {min_int} |
  {empty_set} |
  {integer_set} |
  {real_set} |
  {float_set} |
  {natural_set} |
  {natural1_set} |
  {nat_set} |
  {nat1_set} |
  {int_set} |
  {bool_set} |
  {string_set} |
  {convert_bool} [predicate]:predicate |
  {add} [left]:expression [right]:expression |
  {minus} [left]:expression [right]:expression | // only used by EventB translator
  {minus_or_set_subtract} [left]:expression [right]:expression | // used by this parser 'cause we cannot decide which one it is
  {unary_minus} [expression]:expression |
  {multiplication} [left]:expression [right]:expression | // only used by EventB translator
  {cartesian_product} [left]:expression [right]:expression | // only used by EventB translator
  {mult_or_cart} [left]:expression [right]:expression | // used by this parser 'cause we cannot decide which one it is
  {div} [left]:expression [right]:expression |
  {floored_div} [left]:expression [right]:expression | /* has no concrete syntax, generated for example by TLA translation */
  {if_elsif_expr} [condition]:predicate [then]:expression |
  {if_then_else} [condition]:predicate [then]:expression [elsifs]:expression* [else]:expression |
  {let_expression} [identifiers]:expression* [assignment]:predicate [expr]:expression |
  {modulo} [left]:expression [right]:expression |
  {power_of} [left]:expression [right]:expression |
  {successor} |
  {predecessor} |
  {max} [expression]:expression |
  {min} [expression]:expression |
  {card} [expression]:expression |
  {convert_int_floor} [expression]:expression |
  {convert_int_ceiling} [expression]:expression |
  {convert_real} [expression]:expression |
  {general_sum} [identifiers]:expression* [predicates]:predicate [expression]:expression |
  {general_product} [identifiers]:expression* [predicates]:predicate [expression]:expression |
  {couple} [list]:expression* |
  {comprehension_set} [identifiers]:expression* [predicates]:predicate |
  {symbolic_comprehension_set} [identifiers]:expression* [predicates]:predicate |
  {event_b_comprehension_set} [identifiers]:expression* [expression]:expression [predicates]:predicate | // EventB style
  {symbolic_event_b_comprehension_set} [identifiers]:expression* [expression]:expression [predicates]:predicate |
  {pow_subset} [expression]:expression |
  {pow1_subset} [expression]:expression |
  {fin_subset} [expression]:expression |
  {fin1_subset} [expression]:expression |
  {set_extension} [expressions]:expression* |
  {interval} [left_border]:expression [right_border]:expression |
  {union} [left]:expression [right]:expression |
  {intersection} [left]:expression [right]:expression |
  {set_subtraction} [left]:expression [right]:expression |
  {general_union} [expression]:expression |
  {general_intersection} [expression]:expression |
  {quantified_union} [identifiers]:expression* [predicates]:predicate [expression]:expression |
  {symbolic_quantified_union} [identifiers]:expression* [predicates]:predicate [expression]:expression |
  {quantified_intersection} [identifiers]:expression* [predicates]:predicate [expression]:expression |
  {relations} [left]:expression [right]:expression |
  {identity} [expression]:expression |
  {event_b_identity} | // EventB v 2.0 language only
  {reverse} [expression]:expression |
  {first_projection} [exp1]:expression [exp2]:expression |
  {event_b_first_projection} [expression]:expression | // EventB only
  {event_b_first_projection_v2} | // EventB v 2.0 language only
  {second_projection} [exp1]:expression [exp2]:expression |
  {event_b_second_projection} [expression]:expression | // EventB only
  {event_b_second_projection_v2} | // EventB v 2.0 language only
  {composition} [left]:expression [right]:expression |
  {symbolic_composition} [left]:expression [right]:expression |
  {ring} [left]:expression [right]:expression | // EventB only
  {direct_product} [left]:expression [right]:expression |
  {parallel_product} [left]:expression [right]:expression |
  {iteration} [left]:expression [right]:expression |
  {reflexive_closure} [expression]:expression |
  {closure} [expression]:expression |
  {domain} [expression]:expression |
  {range} [expression]:expression |
  {image} [left]:expression [right]:expression |
  {domain_restriction} [left]:expression [right]:expression |
  {domain_subtraction} [left]:expression [right]:expression |
  {range_restriction} [left]:expression [right]:expression |
  {range_subtraction} [left]:expression [right]:expression |
  {overwrite} [left]:expression [right]:expression |
  {partial_function} [left]:expression [right]:expression |
  {total_function} [left]:expression [right]:expression |
  {partial_injection} [left]:expression [right]:expression |
  {total_injection} [left]:expression [right]:expression |
  {partial_surjection} [left]:expression [right]:expression |
  {total_surjection} [left]:expression [right]:expression |
  {partial_bijection} [left]:expression [right]:expression |
  {total_bijection} [left]:expression [right]:expression |
  {total_relation} [left]:expression [right]:expression | // EventB only
  {surjection_relation} [left]:expression [right]:expression | // EventB only
  {total_surjection_relation} [left]:expression [right]:expression | // EventB only
  {lambda} [identifiers]:expression* [predicate]:predicate [expression]:expression |
  {symbolic_lambda} [identifiers]:expression* [predicate]:predicate [expression]:expression |
  {trans_function} [expression]:expression |
  {trans_relation} [expression]:expression |
  {seq} [expression]:expression |
  {seq1} [expression]:expression |
  {iseq} [expression]:expression |
  {iseq1} [expression]:expression |
  {perm} [expression]:expression |
  {empty_sequence} |
  {sequence_extension} [expression]:expression* |
  {size} [expression]:expression |
  {first} [expression]:expression |
  {last} [expression]:expression |
  {front} [expression]:expression |
  {tail} [expression]:expression |
  {rev} [expression]:expression |
  {concat} [left]:expression [right]:expression |
  {insert_front} [left]:expression [right]:expression |
  {insert_tail} [left]:expression [right]:expression |
  {restrict_front} [left]:expression [right]:expression |
  {restrict_tail} [left]:expression [right]:expression |
  {general_concat} [expression]:expression |
  {definition} [def_literal]:identifier_literal [parameters]:expression* |
  {function} [identifier]:expression [parameters]:expression* |
  {tree} [expression]:expression |
  {btree} [expression]:expression |
  {const} [expression1]:expression [expression2]:expression |
  {top} [expression]:expression |
  {sons} [expression]:expression |
  {prefix} [expression]:expression |
  {postfix} [expression]:expression |
  {sizet} [expression]:expression |
  {mirror} [expression]:expression |
  {rank} [expression1]:expression [expression2]:expression |
  {father} [expression1]:expression [expression2]:expression |
  {son} [expression1]:expression [expression2]:expression [expression3]:expression |
  {subtree} [expression1]:expression [expression2]:expression |
  {arity} [expression1]:expression [expression2]:expression |
  {bin} [expression1]:expression [expression2]:expression? [expression3]:expression? |
  {left} [expression]:expression |
  {right} [expression]:expression |
  {infix} [expression]:expression |
  {struct} [entries]:rec_entry* |
  {rec} [entries]:rec_entry* |
  {record_field} [record]:expression [identifier]:identifier_literal |
  {extended_expr} [identifier]:identifier_literal [expressions]:expression* [predicates]:predicate* | /* Event-B only expression - theory plugin */
  {typeof} [expression]:expression [type]:expression | /* Corresponds to oftype operator in Event-B, was only generated by the translation process */
  {operation_call} [operation]:identifier_literal* [parameters]:expression* |
  {operator} [name]:kw_expression_operator [identifiers]:expression*; // extension for rules

rec_entry = [identifier]:identifier_literal [value]:expression;

/* Substitutions */
substitution =
  {block} [substitution]:substitution |
  {skip} |
  {assign} [lhs_expression]:expression* [rhs_expressions]:expression* |
  {precondition} [predicate]:predicate [substitution]:substitution |
  {assertion} [predicate]:predicate [substitution]:substitution |
  {witness_then} [predicate]:predicate [substitution]:substitution |
  {choice} [substitutions]:substitution* |
  {choice_or} [substitution]:substitution |
  {if} [condition]:predicate [then]:substitution [elsif_substitutions]:substitution* [else]:substitution? |
  {if_elsif} [condition]:predicate [then_substitution]:substitution |
  {select} [condition]:predicate [then]:substitution [when_substitutions]:substitution* [else]:substitution? |
  {select_when} [condition]:predicate [substitution]:substitution |
  {case} expression [either_expr]:expression* [either_subst]:substitution [or_substitutions]:substitution* [else]:substitution? |
  {case_or} [expressions]:expression* [substitution]:substitution |
  {any} [identifiers]:expression* [where]:predicate [then]:substitution |
  {let} [identifiers]:expression* [predicate]:predicate [substitution]:substitution |
  {becomes_element_of} [identifiers]:expression* [set]:expression|
  {becomes_such} [identifiers]:expression* [predicate]:predicate |
  {var} [identifiers]:expression* [substitution]:substitution |
  {sequence} [substitutions]:substitution* |
  {operation_or_definition_call} [expression]:expression |
  {operation_call} [result_identifiers]:expression* [operation]:identifier_literal* [parameters]:expression* |
  {while} [condition]:predicate [do_subst]:substitution [invariant]:predicate [variant]:expression |
  {parallel} [substitutions]:substitution* |
  {definition} [def_literal]:def_literal_substitution [parameters]:expression* |
  {invalid} semicolon |
  {forall_sub_message} [identifiers]:expression* [where]:predicate [expect]:predicate [error_type]:integer_literal? [on_success]:expression? [message]:expression | // extension for rules
  {rule_fail_sub} [identifiers]:expression* [when]:predicate? [error_type]:integer_literal? [message]:expression | // extension for rules
  {for_loop} [identifiers]:expression* [set]:expression [do_subst]:substitution | // extension for rules
  {operator} [name]:kw_substitution_operator [arguments]:expression* | // extension for rules
  {define} [name]:identifier_literal [type]:expression [dummy_value]:expression? [value]:expression; // extension for rules




© 2015 - 2024 Weber Informatics LLC | Privacy Policy