最近幾年的項目技術難點都和編譯原理,抽象語法樹,代碼編輯器 有關係。如今時間有點空,先從基礎瞭解起來,讓有些交互和提示可以更智能些。javascript
編譯原理 其實就是 讓計算機懂的 「437+734」 這樣的字符串編程 sum 437, 734 計算機懂得的機器碼。實際場景中多是從一種高級語言編譯成一種低級語言。html
編譯過程份成2個步驟:前端
1.詞法分析java
詞法分析就是 經過定義的正則表達式,把輸入的字符串變成一個個標記(token)。node
「437+734」 => NUM PLUS NUMreact
2.語法分析git
根據定於的語法,把上邊的token經過移進/歸約自動機,一步步的移入,規約,變成抽象語法樹,最終產生結構。github
文法 E => NUM PLUS NUM => sum(437, 734);正則表達式
這個編譯代碼的程序咱們叫作解析器,分析器,Parser。express
在實際狀況中,有專門用來生成Parser的程序,解析器生成器。
前端的js語法分析器生成器,仍是瞞多的 https://tomassetti.me/parsing-in-javascript/,不一樣的語法生成器支持的文法也有差異。
項目中用到的是jison庫,這個庫支持(lr0, slr, lr1, ll, lalr)文法。通常咱們程序中使用的是lalr文法。
能夠經過debugger的方式去理解移入規約的過,和jison的使用。http://nolanlawson.github.io/jison-debugger/。
使用起來很簡單,官網的文檔也比較詳細, http://zaa.ch/jison/docs/。定義jison文件,經過 node 命令 "jison 文件"生成Parser的js文件;
jison是bison在js端的實現,可是也不是徹底實現了相關的功能。
從http://nolanlawson.github.io/jison-debugger/上就能看到下面的一些文法格式
/* 詞法文法 */ %lex /* 選項設置 flex 最長匹配原則 case-insensitive 忽略大小寫 */ %options flex case-insensitive %% \s+ /* skip whitespace */ [0-9]+("."[0-9]+)?\b return 'NUMBER' <<EOF>> return 'EOF' /lex /*操做符優先級設置*/ %left '+' '-' %left '*' '/' /*語法開始的非終結符號*/ %start expressions %% /* 詞法 */ expressions : e EOF {return $1;} ;
試了下http://dinosaur.compilertools.net/bison/bison_10.html#SEC84,bison文檔上面的這個文法不支持,因此使用的時候本身要看着處理
2.jison的輸出
jison生成的Parser的輸出實際上是文法本身定義的,能夠是一個結果值,能夠是ast樹,也能夠是用戶本身在文法上面定義的結果
3.Parser.js
其實這個能夠直接研究下源代碼,源代碼看起來雖然有些難度,主要是語法分析的邏輯,移入規則邏輯,標示符,終結符,非終結符號等等相關的定義,其餘詞法的邏輯。
和實際使用中的有的一些變量仍是比較容易看懂,或者說debug一下大概就知道有哪些參數了。
文法定義中的參數
yy: 這個屬性是用戶本身定義的,在編譯期間共享,這樣也是代碼更加靈活。
4.誤區
在使用中,會有一些誤區存在,特別是移入規約的順序,可能和咱們平時看代碼存在差別。好比說上面的例子。
咱們須要在RULE{expr}中的expr內容 有另一種含義,
可是實際狀況的執行順序實際上是先 expr規則規約,纔是 RULE{expr}規則規約,因此在進行expr規約的時候並不知道它是在RULE{}裏面的,因此咱們經過Parser生成ast,再經過ast遍從來解決這個問題可能會更好一些。