如何用JavaScript编写一个高效的词法分析器和语法解析器?

词法解析器实现得很好。
看看这个正则表达式。
是不是感觉像小时候玩魔方一样?每面都涂有不同的颜色,现在你需要快速找到特定的色块。
例如,/^d+(.d+)?/ 匹配此数字。
d+ 是一个数字,后跟一个可选的小数点和一个数字。
这样您就可以捕获 1 2 3 或 3 .1 4 等内容。

但说实话,我不明白你写的那行代码 constexpr=parseAdditive();当时在 parsePrimary() 中。
应该是 left = parseAdditive();正确的?这种地方很容易出事。
另外,如果peek()在expect(type)函数中返回null,peek()?.type将变成undefined?.type,这将导致错误。
最好改成 if (!peek() || peek().type !== type) 这样更安全。

DFA(确定性有限状态机)优化建议非常好。
想象一下,您已经到达一个十字路口,并且有一个红绿灯。
绿灯走,红灯停,不要盲目冲。
比如匹配数字时,如果当前字母是数字,就一直向后走,遇到不是数字的就停下来。
这比常规匹配更有效。

句法解析器的递归下降方法类似于下棋。
你采取的每一步都取决于下一步。
例如,因式分解 3 + 4 5 时,先看 3 ,将其视为 NumberLiteral,然后看 +,知道优先级较低,所以先将 3 向左因式分解,然后再看 4 5 ,这是另一个乘法,将 4 向左因式分解,5 向右分解,最后将它们视为运算符将它们组合起来。
就像你下棋时,你看的是一招、三招。

错误处理期间跳过了同步点,这非常有用。
例如用户输入代码if(x = 1 0),正常会报错,但可以跳过=,搜索then else,这样会提示用户将=改为==。
Babel 分析器真的很酷。
它包含一个称为 template-literal-tokenizer 的词法解析器,专门处理模板字符串。
你可以了解她的想法。

您的 tokens.push({type,value:match[0]}) 行代码确实可以优化。
例如,match[0]始终等于input.slice(pos).match(pattern)第一次匹配的结果,因此可以直接使用match[0]来对value进行赋值,减少单个变量的创建。
同样,pos+=match[0].length可以改为pos += match[0].length;它更加简洁。

另外,对于名称functioncreateTokenizer(input),最好使用const而不是let,因为这部分解析器代码不会改变,而且使用const更加规范。
至于token数组,可以考虑从一开始就预先分配固定大小,如 const tokens = new Array(input.length / 5 );让 pos = 0;这可以减少动态缩放性能的损失。

最后一个函数parseMultiplicative(),里面left = parsePrimary();这行代码可以组合成 left = parsePrimary(); while (peek()?.type === 'STAR' || peek()?.type === 'SLASH') { const op =advanced(); const right = parsePrimary(); left = { type: 'BinaryExpression', 操作符: op.value, left, right };这更加紧凑。
但请注意,如果用户输入非法代码,例如 3 4 ,则可能会无限期重复。
最好添加一个计数器以防止无限循环。

总的来说,你的实现思路是正确的。
词法解析器就像切菜,句法解析器就像煮菜。
你先把蔬菜切碎,然后按顺序炒。
但做饭时要小心。
例如,如果优先级太低,锅会烧焦,如果优先级太高,则无法正常烹饪。

使用 Tree-sitter JavaScript 解析器提取函数名

那天我坐在咖啡馆里,看着电脑屏幕,思考着代码。
坐在树上的事情听起来很高级,但实际上这真的就像一层一层地剥洋葱一样。
我编写了一个小脚本并首先运行代码: const parser = new Parser();解析器.setLanguage(JavaScript);然后添加 function foo() {} 作为测试用例。
屏幕上出现了['foo'],我的心猛地一跳——真的有效!
但很快就发现会有麻烦。
我还添加了 bar() {} 函数,并且只输出了 foo 。
更改了递归函数 if(node.type === 'function_declaration') 后突然发现 functionnested() {} 等嵌套函数仍然缺失。

查了半天namedChildren属性,发现tree-sitter节点有不同的子节点类型,并且函数名隐藏在标识符中。
真正关心的是函数表达式。
const baz = 函数 qux() {}; 'function_declaration') 使用“赋值表达式”。





本能抓到抢劫和凹陷函数了{} }这些,Tree-sitter的节点类型不支持直接识别。
我又去改代码,把function_解释。

坐在椅子上,看着屏幕上乱跳的调试信息,突然想到:也许Tree Sitter的文档里根本没讲这些复杂的场景? 还是应该用正则表达式来找出来?

JavaScript中HTML实体字符解码:利用DOM解析器还原特殊字符

ရိုးရိုးသားသားပြောရရင် ဒါက တော်တော်စိတ်ဝင်စားဖို့ကောင်းတယ်။ JS ရှိ HTML အစိတ်အပိုင်းများကို ကုဒ်ဆွဲခြင်းသည် အဓိကအားဖြင့် ဘရောက်ဆာ၏ ကိုယ်ပိုင် DOM ခွဲခြမ်းစိတ်ဖြာခြင်းအပေါ် မူတည်သည်။你看到၎င်းသည် အထူးသင်္ကေတများကို သူ့ဘာသာသူ ပုံမှန်စကားလုံးများအဖြစ်သို့ ပြောင်းလဲနိုင်သည်။
例如,在这个例子中:首先创建一个临时div元素;然后将字符串插入到内部 HTML 中。
这时,ဘရောင်ဇာသည် အရာဝတ္ထုများကို အက္ခရာအဖြစ် အလိုအလျောက် ပြောင်းလဲပေးလိမ့်မည်။然后,通过内部文本引用,您将获得转换后的文本。
就是这么简单。

我附上代码给你: JavaScript const tempDiv = document.createElement('div'); tempDiv[xss_clean] = 'pok&2 3 3 ;mon'; console.log(tempDiv.innerText); // 输出:精灵
缓解问题;它可以用封闭物覆盖: JavaScript const NormalizeText = (() => { const tempDiv = document.createElement('div'); 返回(代码)=> { tempDiv[xss_clean] = 代码文本 返回 tempDiv.innerText; }; })(); JavaScript console.log(normalizeText('pok&2 3 3 ;mon')); // 神奇宝贝 console.log(normalizeText('&x2 6 05 ;Star')); // ★星
但请注意几点: 1 、这个只能在浏览器中使用; Node.js 需要cheerio 或jsdom。
2 [xss_clean] ကိုတိုက်ရိုက်လည်ပတ်ရာတွင် XSS အန္တရာယ်များရှိသည်၊然而,这里我们只取innerText;是比较安全的。
3 . 不要使用这么大的数据量,效率不会随之而来 4 . 确保它是UTF-8 编码。
သို့မဟုတ်ပါက ၎င်းသည် ဗလုံးဗထွေးဖြစ်လိမ့်မည်
ဘုံအရာများ- 2 3 3 ;၊ &xE9 ;,如十六进制 é。

它可以手动使用,也可以使用 Node.js。
例如: JavaScript const he = require('he'); console.log(he.decode('pok&2 3 3 ;mon')); // 神奇宝贝
一般来说, ဘရောက်ဆာပတ်ဝန်းကျင်တွင် DOM 解析器 + ပိတ်ခြင်းကို အသုံးပြုရန်这是最合适的。
解析innerHTML和innertext得到结果,禁用可以提高性能。
适合处理在幕后传递的实体编码字符串。