成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

六十行代碼完成 四則運(yùn)算 語(yǔ)法解析器

劉永祥 / 1390人閱讀

摘要:生成語(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

相關(guān)文章

  • 【Python從入門到精通】五萬(wàn)千字對(duì)Python基礎(chǔ)知識(shí)做一個(gè)了結(jié)吧?。ǘ耍局档檬詹亍?/b>

    摘要:它是一門解析型的語(yǔ)言,何為解析型語(yǔ)言呢就是在運(yùn)行時(shí)通過(guò)解析器將源代碼一行行解析成機(jī)器碼。而像語(yǔ)言,等則是編譯型的語(yǔ)言,即通過(guò)編譯器將所有的源代碼一次性編譯成二進(jìn)制指令,生成一個(gè)可執(zhí)行的程序。 ...

    leeon 評(píng)論0 收藏0
  • Python 進(jìn)階之路 (十一) 再立Flag, 社區(qū)最全的itertools深度解析(下)

    摘要:將每一行作為返回,其中是每行中的列名。對(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)化,希望有更好主意...

    tomorrowwu 評(píng)論0 收藏0
  • 第6章:可維護(hù)性軟件構(gòu)建方法 6.3可維護(hù)性構(gòu)建技術(shù)

    摘要:遵循特定規(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)...

    young.li 評(píng)論0 收藏0
  • React系列 --- 從使用React了解Css的各種使用方案()

    摘要:當(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...

    freecode 評(píng)論0 收藏0
  • JavaScript 編程精解 中文第三版 十二、項(xiàng)目:編程語(yǔ)言

    摘要:來(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 自豪地采用...

    Near_Li 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

劉永祥

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<