ocamlyacc + ocamllex

というわけで、無事、ocaml環境の構築が終わったので、早速CSSの解析ルーチンを作ってみました。
使ったのは、ocamlyaccとocamllexです。
下のような感じにコードを書いてみました。(とりあえずは、いい加減なことには目を瞑ってください)

[lexer.mll]
{
open Parser
exception Eof
}
rule token = parse
    [' ' '\t' '\n']                               { token lexbuf }
  | "@charset" [^'\n']* '\n'                      { token lexbuf }
  | "/*" [^'/']* "*/"                             { token lexbuf }
  | ['a' - 'z' 'A' - 'Z' '0' - '9' '#' '.' '-' '%']+ 
                                                  { SYMBOL(Lexing.lexeme lexbuf) }
  | '{'                                           { LPAREN }
  | '}'                                           { RPAREN }
  | ':'                                           { COLON }
  | ';'                                           { SEMICOLON }
  | ','                                           { COMMA }
  | eof                                           { raise Eof }
  | _                                             { print_string (Lexing.lexeme lexbuf); raise Eof }
[parser.mly]
%token <string> SYMBOL
%token LPAREN RPAREN COLON SEMICOLON COMMA
%start main
%type <string> main
%%
main:
    list_selector LPAREN list_declare RPAREN      { "====" ^ $1 ^ "====\n" ^ $3 ^ "========\n" }
;
list_selector:
    symbl                                         { $1 }
  | list_selector symbl                           { $1 ^ " " ^ $2 }
  | list_selector COMMA list_selector             { $1 ^ " & " ^ $3 }
;
list_declare:
    declare                                       { $1 }
  | list_declare declare                          { $1 ^ $2 }
;
declare:
    symbl COLON value SEMICOLON                   { "** " ^ $1 ^ " **\n" ^ $3 ^ "\n" }
;
value:
    symbl                                         { $1 }
  | value symbl                                   { $1 ^ "\n" ^ $2 }
;
symbl:
    SYMBOL                                        { $1 }
;
[sample.ml]
let _ =
  try
    let lexbuf = Lexing.from_channel stdin in
    while true do
      let result = Parser.main Lexer.token lexbuf in
      print_string result;
      flush stdout
    done
  with Lexer.Eof -> exit 0

コンパイルして、「sample.exe < sample.css」で実行してやると、動きました。出力は、こんな感じ。

====#main p====
** margin **
0
** padding **
0
0
0.5ex
** text-indent **
1em
========
====#main ul & #main ol====
** margin **
1ex
0
1.5ex
** padding **
0
0
0
4em
========