--- /dev/null
+%{
+
+module S = Str
+module L = List
+module T = Table
+
+let split s =
+ S.split (S.regexp "[ \r\n\t]+") s
+
+let mk_atom s rs =
+ let map c (b, (x1, x2)) = c, b, x1, x2 in
+ L.map (map (split s)) rs
+
+%}
+
+%token <int> NUM
+%token <string> TEXT
+%token NAME TABLE CSS SR OC CC OB CB PS EOF
+
+%start script
+%type <(string * Table.table * Css.atoms) list> script
+
+%%
+
+text:
+ | TEXT { $1 }
+
+texts:
+ | text { [$1] }
+ | text PS texts { $1 :: $3 }
+;
+
+key:
+ | texts { T.Text $1 }
+ | SR { T.Glue None }
+ | NUM { T.Glue (Some $1) }
+;
+
+css:
+ | { [] }
+ | CSS TEXT { split $2 }
+;
+
+table:
+ | css key { T.mk_key $2 $1 }
+ | css OC tables CC { T.mk_line false $3 $1 }
+ | css OB tables CB { T.mk_line true $3 $1 }
+;
+
+tables:
+ | { [] }
+ | table tables { $1 :: $2 }
+;
+
+name:
+ | { "" }
+ | NAME TEXT { $2 }
+;
+
+interval:
+ | NUM { Some $1, Some $1 }
+ | SR { None, None }
+ | NUM NUM { Some $1, Some $2 }
+ | NUM SR { Some $1, None }
+ | SR NUM { None, Some $2 }
+ | SR SR { None, None }
+;
+
+range:
+ | OB interval CB { true, $2 }
+ | OC interval CC { false, $2 }
+;
+
+ranges:
+ | { [] }
+ | range ranges { $1 :: $2 }
+;
+
+atom:
+ | CSS TEXT ranges { mk_atom $2 $3 }
+;
+
+atoms:
+ | { [] }
+ | atom atoms { $1 @ $2 }
+;
+
+directive:
+ | name TABLE table atoms { $1, $3, $4 }
+;
+
+script:
+ | EOF { [] }
+ | directive script { $1 :: $2 }
+;