%{ open Ast %} %token INT %token RAT %token STR %token NAME %token LABEL %token REFERENCE %token LBRACKET RBRACKET LBRACE RBRACE LPAREN RPAREN HASH_LPAREN %token BAR AND OR NOT EOF %start program %% program: | statements = list(statement); EOF { statements } statement: | head = NAME; args = nonempty_list(binding) { Directive (head, args) } | b = block { Assert b } binding: | label = LABEL; value = node { (label, value) } (* :or binds looser than :and; both associate to the left. The grouping form is ordinary parentheses. *) node: | left = node; OR; right = conjunction { Or (left, right) } | conj = conjunction { conj } conjunction: | left = conjunction; AND; right = operand { And (left, right) } | left = conjunction; NOT; right = operand { Not (left, right) } | operand = operand { operand } operand: | b = block { b } | name = NAME { Name name } | n = INT { Int n } | r = RAT { Rat (fst r, snd r) } | s = STR { Str s } | r = REFERENCE { Ref r } | LBRACE; fields = nonempty_list(binding); RBRACE { Record fields } | HASH_LPAREN; items = list(operand); tail = option(seq_tail); RPAREN { Seq (items, tail) } | LPAREN; n = node; RPAREN { n } seq_tail: | BAR; tail = operand { tail } block: | LBRACKET; head = NAME; args = list(binding); RBRACKET { Block (head, args) }