Feature image

从CoffeeScript源代码中获取文法并可视化

最近在研究把CoffeeScript编译到.Net CLR环境上运行的可能性,在几个CoffeeScript compiler的实现中,没有发现对文法定义的specification,如果要人肉重建不仅工作量忧桑,还有可能导致兼容性问题。于是看了下源代码,发现略施小计就能解决这个问题。

CoffeeScript的Parser使用jison生成的,所有的文法都在grammar.coffee里定义了。这个代码非常好改,去掉对jison的调用,把语法定义用JSON.stringify() format了再输出,执行修改后的代码

1
coffee grammar.coffee

就会得到一大串jison格式的文法定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"tokens":" TERMINATOR TERMINATOR TERMINATOR STATEMENT INDENT OUTDENT INDENT OUTDENT IDENTIFIER NUMBER STRING JS REGEX BOOL = = INDENT OUTDENT : : INDENT OUTDENT RETURN RETURN HERECOMMENT PARAM_START PARAM_END -> => , , ... = ... . ?. :: :: INDEX_START INDEX_END INDEX_SOAK { } , TERMINATOR INDENT OUTDENT CLASS CLASS CLASS EXTENDS CLASS EXTENDS CLASS CLASS CLASS EXTENDS CLASS EXTENDS SUPER SUPER FUNC_EXIST CALL_START CALL_END CALL_START CALL_END THIS @ @ [ ] [ ] .. ... [ ] , TERMINATOR INDENT OUTDENT INDENT OUTDENT , TRY TRY TRY FINALLY TRY FINALLY CATCH THROW ( ) ( INDENT OUTDENT ) WHILE WHILE WHEN UNTIL UNTIL WHEN LOOP LOOP FOR FOR FOR OWN , FORIN FOROF FORIN WHEN FOROF WHEN FORIN BY FORIN WHEN BY FORIN BY WHEN SWITCH INDENT OUTDENT SWITCH INDENT ELSE OUTDENT SWITCH INDENT OUTDENT SWITCH INDENT ELSE OUTDENT LEADING_WHEN LEADING_WHEN TERMINATOR IF ELSE IF ELSE POST_IF POST_IF UNARY - + -- ++ -- ++ ? + - MATH SHIFT COMPARE LOGIC RELATION COMPOUND_ASSIGN COMPOUND_ASSIGN INDENT OUTDENT EXTENDS",
"bnf":
{
"Root":
[
["","return $$ = new yy.Block;",null],
["Body","return $$ = $1;",null],
["Block TERMINATOR","return $$ = $1;",null]
],
"Body":
[
["Line","$$ = yy.Block.wrap([$1]);",null],
["Body TERMINATOR Line","$$ = $1.push($3);",null],
["Body TERMINATOR","$$ = $1;",null]
],
"Line":
[
["Expression","$$ = $1;",null],
["Statement","$$ = $1;",null]
],
...

这样已经算是可用了,但可读性依然不高,经过一番搜索发现一个jison-to-w3c文法标记格式的转换器,得到文法

1
Root     ::= Body?
Body     ::= Line ( TERMINATOR Line | TERMINATOR )*
Line     ::= Expression
           | Statement
Statement
         ::= Return
           | Comment
           | STATEMENT
Expression
         ::= Value
           | Invocation
           | Code
           | Operation
           | Assign
           | If
           | Try
           | While
           | For
           | Switch
           | Class
           | Throw
...

最后找到一个可视化文法的网站Railroad Diagram Generator将其可视化,just for fun:

coffee-grammar

完整的图在:http://project.catx.me/other/coffee-grammar.xhtml

源代码+完整的文法定义:https://gist.github.com/akfish/8827385