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 ========