摘要:生成語(yǔ)法解析器五個(gè)文法,行代碼搞定,表示四則運(yùn)算的文法,可以參考此文。這些相互依賴的文法組成了一個(gè)文法鏈條,完整表達(dá)了四則運(yùn)算的邏輯函數(shù)第一個(gè)參數(shù)接收根文法表達(dá)式,第二個(gè)參數(shù)是詞法解析器,我們將上面創(chuàng)建的傳入。
syntax-parser 是完全利用 JS 編寫的詞法解析+語(yǔ)法解析引擎,所以完全支持在瀏覽器、NodeJS 環(huán)境執(zhí)行。
它可以幫助你快速生成 詞法解析器,亦或進(jìn)一步生成 語(yǔ)法解析器,將字符串解析成語(yǔ)法樹(shù),語(yǔ)法解析器還支持下一步智能提示功能,輸入光標(biāo)位置,給出輸入推薦。
目前 syntax-parser 功能逐漸穩(wěn)定,內(nèi)核性能還在逐步優(yōu)化中,我們會(huì)利用 syntax-parser 引擎的能力,完成一些令人驚喜的小 DEMO,如果與你的業(yè)務(wù)場(chǎng)景恰好契合,歡迎使用!
這次的 DEMO 是:利用 syntax-parser 快速完成四則運(yùn)算語(yǔ)法解析器!
1. 生成詞法解析器通過(guò)下面 20 行配置,生成一個(gè)能解析英文、數(shù)字、加減乘除、左右括號(hào)的詞法解析器,so easy!
import { createLexer } from "syntax-parser" const myLexer = createLexer([ { type: "whitespace", regexes: [/^(s+)/], ignore: true }, { type: "word", regexes: [/^([a-zA-Z0-9]+)/] // 解析數(shù)字 }, { type: "operator", regexes: [ /^((|))/, // 解析 ( ) /^(+|-|*|/)/ // 解析 + - * / ] } ]);
我們可以使用 myLexer 將字符串解析為一個(gè)個(gè) Token:
myLexer("1 + 2 - 3 * b / (x + y)")
不過(guò)這次的目的是生成語(yǔ)法樹(shù),所以我們會(huì)把 myLexer 作為參數(shù)傳給語(yǔ)法解析器。
2. 生成語(yǔ)法解析器五個(gè)文法,20 行代碼搞定,表示四則運(yùn)算的文法,可以參考 此文。
利用 chain ,可以高效表示每一個(gè)文法表達(dá)式要匹配的字符串、表示匹配次數(shù),還支持嵌入新的文法函數(shù)。這些相互依賴的文法組成了一個(gè)文法鏈條,完整表達(dá)了四則運(yùn)算的邏輯:
import { chain, createParser, many, matchTokenType } from "syntax-parser" const root = () => chain(term, many(addOp, root))(parseTermAst); const term = () => chain(factor, many(mulOp, root))(parseTermAst); const mulOp = () => chain(["*", "/"])(ast => ast[0].value); const addOp = () => chain(["+", "-"])(ast => ast[0].value); const factor = () => chain([ chain("(", root, ")")(ast => ast[1]), chain(matchTokenType("word"))(ast => ast[0].value) ])(ast => ast[0]); const myParser = createParser( root, // Root grammar. myLexer // Created in lexer example. );
createParser 函數(shù)第一個(gè)參數(shù)接收根文法表達(dá)式,第二個(gè)參數(shù)是詞法解析器,我們將上面創(chuàng)建的 myLexer 傳入。 parseTermAst 函數(shù)多帶帶提出來(lái),目的是輔助生成語(yǔ)法樹(shù),一共 20 行代碼:
const parseTermAst = (ast: any) => ast[1] ? ast[1].reduce( (obj: any, next: any) => next[0] ? { operator: next[0], left: obj || ast[0], right: next[1] } : { operator: next[1] && next[1].operator, left: obj || ast[0], right: next[1] && next[1].right }, null ) : ast[0];
這個(gè)函數(shù)是為了將語(yǔ)法樹(shù)變得更規(guī)整,否則得到的 AST 解析將會(huì)是數(shù)組,而不是像 left right operator 這么有含義的對(duì)象。
PS:本文的 DEMO 沒(méi)有考慮乘除高優(yōu)先級(jí)問(wèn)題。3. 運(yùn)行詞法解析器
最后得到的 myParser 就是語(yǔ)法解析器了!直接執(zhí)行就能拿到語(yǔ)法樹(shù)結(jié)果!
const result = myParser("1 + 2 - (3 - 4 + 5) * 6 / 7"); console.log(result.ast)
我們打印出語(yǔ)法樹(shù),運(yùn)行結(jié)果如下:
{ "operator": "/", "left": { "operator": "-", "left": { "operator": "+", "left": "1", "right": "2" }, "right": { "operator": "*", "left": { "operator": "+", "left": { "operator": "-", "left": "3", "right": "4" }, "right": "5" }, "right": "6" } }, "right": "7" }4. 錯(cuò)誤提示
不僅語(yǔ)法樹(shù),我們構(gòu)造一個(gè)錯(cuò)誤的輸入試試!
const result = myParser("1 + 2 - (3 - 4 + 5) * 6 / "); console.log(result.error)
這次我們打印錯(cuò)誤信息:
{ "suggestions": [ { "type": "string", "value": "(" }, { "type": "special", "value": "word" } ], "token": { "type": "operator", "value": "/", "position": [ 24, 25 ] }, "reason": "incomplete" }
精準(zhǔn)的提示了最后一個(gè) / 位置不完整,建議是填寫 ( 或者一個(gè)單詞。這都是根據(jù)文法自動(dòng)生成的建議,提示不多一個(gè),不少一個(gè)!
5. 任意位置輸入提示最精髓的功能到了,這個(gè)語(yǔ)法解析器就是為了做自動(dòng)提示,所以支持多傳一個(gè)參數(shù),告訴我當(dāng)前你光標(biāo)的位置:
const result = myParser("1 + 1", 5) console.log(result.nextMatchings)
假設(shè)語(yǔ)句寫到這里,我們光標(biāo)位置定位到 5 的位置,也就是最后一個(gè) 1 后面,nextMatchings 屬性會(huì)告訴我們后面的可能情況:
[ { "type": "string", "value": "-" }, { "type": "string", "value": "+" }, { "type": "string", "value": "/" }, { "type": "string", "value": "*" } ]6. 結(jié)合業(yè)務(wù),用在文本編輯器
筆者拿 monaco-editor 舉例,利用上面的語(yǔ)法樹(shù)解析,我們可以輕松完成下面的效果:
光標(biāo)智能補(bǔ)全 錯(cuò)誤提示無(wú)論是智能補(bǔ)全,還是錯(cuò)誤提示都是 100% 精準(zhǔn)無(wú)誤的(根據(jù)上面編寫的文法表達(dá)式)。
相比普通的語(yǔ)法解析器在解析錯(cuò)誤時(shí)直接拋出錯(cuò)誤,syntax-parser 不僅提供語(yǔ)法樹(shù),還能根據(jù)文法智能提示光標(biāo)位置的輸入推薦,哪怕是輸入錯(cuò)誤的情況下,是不是解決了大家的痛點(diǎn)呢?如果覺(jué)得好用,歡迎給 syntax-parser 提 建議 或者 pr !
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/97674.html
摘要:它是一門解析型的語(yǔ)言,何為解析型語(yǔ)言呢就是在運(yùn)行時(shí)通過(guò)解析器將源代碼一行行解析成機(jī)器碼。而像語(yǔ)言,等則是編譯型的語(yǔ)言,即通過(guò)編譯器將所有的源代碼一次性編譯成二進(jìn)制指令,生成一個(gè)可執(zhí)行的程序。 ...
摘要:將每一行作為返回,其中是每行中的列名。對(duì)于每一行,都會(huì)生成一個(gè)對(duì)象,其中包含和列中的值。它返回一個(gè)迭代器,是迭代結(jié)果都為的情況。深度解析至此全劇終。 簡(jiǎn)單實(shí)戰(zhàn) 大家好,我又來(lái)了,在經(jīng)過(guò)之前兩篇文章的介紹后相信大家對(duì)itertools的一些常見(jiàn)的好用的方法有了一個(gè)大致的了解,我自己在學(xué)完之后仿照別人的例子進(jìn)行了真實(shí)場(chǎng)景下的模擬練習(xí),今天和大家一起分享,有很多部分還可以優(yōu)化,希望有更好主意...
摘要:遵循特定規(guī)則,利用操作符,終止節(jié)點(diǎn)和其他非終止節(jié)點(diǎn),構(gòu)造新的字符串非終結(jié)符是表示字符串的樹(shù)的內(nèi)部節(jié)點(diǎn)。語(yǔ)法中的生產(chǎn)具有這種形式非終結(jié)符終結(jié),非終結(jié)符和運(yùn)算符的表達(dá)式語(yǔ)法的非終結(jié)點(diǎn)之一被指定為根。 大綱 基于狀態(tài)的構(gòu)建 基于自動(dòng)機(jī)的編程 設(shè)計(jì)模式:Memento提供了將對(duì)象恢復(fù)到之前狀態(tài)的功能(撤消)。 設(shè)計(jì)模式:狀態(tài)允許對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變其行為。 表驅(qū)動(dòng)結(jié)構(gòu)* 基于語(yǔ)法的構(gòu)...
摘要:當(dāng)然這不是只限于使用或者其他打包工具的方式都能支持使用優(yōu)點(diǎn)模塊化和可重用性沒(méi)有沖突顯性依賴不會(huì)污染全局可以配合預(yù)處理器使用少開(kāi)發(fā)單獨(dú)文件寫法基本一致 To define is to limit. 定義一樣?xùn)|西,就意味著限制了它?!鯛柕?《道林·格雷的畫像》 React系列 React系列 --- 簡(jiǎn)單模擬語(yǔ)法(一)React系列 --- Jsx, 合成事件與Refs(二)Reac...
摘要:來(lái)源編程精解中文第三版翻譯項(xiàng)目原文譯者飛龍協(xié)議自豪地采用谷歌翻譯部分參考了編程精解第版確定編程語(yǔ)言中的表達(dá)式含義的求值器只是另一個(gè)程序。若文本不是一個(gè)合法程序,解析器應(yīng)該指出錯(cuò)誤。 來(lái)源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項(xiàng)目原文:Project: A Programming Language 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 自豪地采用...
閱讀 1346·2021-11-15 11:37
閱讀 2225·2021-09-23 11:21
閱讀 1309·2019-08-30 15:55
閱讀 2116·2019-08-30 15:55
閱讀 2825·2019-08-30 15:52
閱讀 2830·2019-08-30 11:12
閱讀 1583·2019-08-29 18:45
閱讀 1897·2019-08-29 14:04