如何在 PEG.js 中为解析结果生成十进制、十六进制与二进制多行输出

3次阅读

如何在 PEG.js 中为解析结果生成十进制、十六进制与二进制多行输出

本文详解如何在 peg.js 语法规则中通过语义动作(semantic actions)动态计算并格式化表达式结果,实现单次解析后按行输出十进制、十六进制和二进制三种表示形式,并支持多行输入与对应多行输出。

本文详解如何在 peg.js 语法规则中通过语义动作(semantic actions)动态计算并格式化表达式结果,实现单次解析后按行输出十进制、十六进制和二进制三种表示形式,并支持多行输入与对应多行输出。

PEG.js 允许在语法规则末尾添加 JavaScript 语义动作(即花括号 {…} 中的代码),用于自定义匹配后的返回值。要实现如 (3*(5+8)) → 39n27n00100111 的三行输出(十进制、十六进制小写无前缀、二进制八位补零),关键在于:在顶层表达式规则的语义动作中,对计算结果执行三次格式化,并用换行符 n 连接

以下是一个完整、可运行的 PEG.js 示例(适配最新 PEG.js v0.10+):

// arithmetic.pegjs Start   = _ expr:Expression _ { return formatResult(expr); }  Expression   = left:Term op:("+" / "-") right:Expression     { return op === "+" ? left + right : left - right; }   / Term  Term   = left:Factor op:("*" / "/") right:Term     { return op === "*" ? left * right : left / right; }   / Factor  Factor   = "(" _ expr:Expression _ ")" { return expr; }   / number:Integer { return number; }  Integer   = digits:[0-9]+ { return parseInt(digits.join(""), 10); }  _ "whitespace"   = [ tnr]*  // 辅助函数:统一格式化数值结果 formatResult = (value) => {   const dec = String(value);   const hex = value.toString(16).toLowerCase(); // 如:39 → "27"   const bin = value.toString(2).padStart(8, "0"); // 补零至8位:39 → "00100111"   return `${dec}n${hex}n${bin}`; };

使用说明

  • 将上述语法粘贴至 PEG.js Online Editor 或本地构建工具中;
  • 输入 (3*(5+8)),解析结果将严格输出为:
    39 27 00100111
  • 支持多行输入(如 15n(2+3)),只要主规则 Start 匹配完整表达式(或扩展为 Start = __ expr:(Expression / “”) __ 并循环处理),即可逐行解析并拼接输出(需在生成器代码中额外处理换行分隔逻辑)。

⚠️ 注意事项

  • parseInt(text(), 10) 在原始答案中存在风险:text() 返回原始字符串(含空格/括号),应避免直接调用;本例采用结构化解析(Integer 规则先提取纯数字再转换),更健壮;
  • 二进制补零位数(如 padStart(8, “0”))可根据需求调整(16、32 或动态适配);
  • 若需十六进制带 0x 前缀或大写,改用 value.toString(16).toUpperCase().padStart(2, “0”);
  • PEG.js 不原生支持多入口匹配,如需批量处理多行输入,建议在调用 parser.parse(input) 后,用 input.split(‘n’).map(line => parser.parse(line.trim())).join(‘n’) 封装

掌握语义动作与 JavaScript 类型转换的组合,即可灵活控制 PEG.js 的任意输出形态——从调试信息到机器可读格式,皆在一“return”之间。

text=ZqhQzanResources