如何在 PEG.js 语法中为表达式结果生成十进制、十六进制与二进制的多行输出

3次阅读

如何在 PEG.js 语法中为表达式结果生成十进制、十六进制与二进制的多行输出

本文详解如何通过 peg.js 的语义动作(semantic actions)自定义解析结果,将算术表达式计算值格式化为十进制、十六进制和二进制三行字符串输出,并支持多行输入与独立结果分隔。

本文详解如何通过 peg.js 的语义动作(semantic actions)自定义解析结果,将算术表达式计算值格式化为十进制、十六进制和二进制三行字符串输出,并支持多行输入与独立结果分隔。

PEG.js 默认将匹配结果作为 JavaScript 值返回,而其核心优势之一在于:你可在每条语法规则末尾添加 { … } 语义动作,完全控制该规则的返回值。要实现“一行输入 → 三行输出(Decimal/Hex/Bin)”,关键在于:在最终求值规则中执行计算,并用换行符 n 拼接三种进制格式字符串

以下是一个完整、可运行的示例语法(兼容 PEG.js v0.10+):

// arithmetic.pegjs Start   = _ expr:Expression _ { return expr; }  Expression   = left:Term op:("+" / "-") right:Expression     { const l = number(left); const r = Number(right);       return op === "+" ? l + r : l - r; }   / Term  Term   = left:Factor op:("*" / "/") right:Term     { const l = Number(left); const r = Number(right);       return op === "*" ? l * r : (r !== 0 ? l / r : NaN); }   / Factor  Factor   = "(" _ expr:Expression _ ")" { return expr; }   / number:Integer { return number; }  Integer   = digits:[0-9]+ {       const n = parseInt(digits.join(''), 10);       // 生成三行:十进制(原样)、十六进制(小写前缀 0x,补零至2位)、二进制(补零至8位)       const hex = '0x' + n.toString(16).padStart(2, '0');       const bin = n.toString(2).padStart(8, '0');       return `${n}n${hex}n${bin}`;     }  _ "whitespace"   = [ tnr]*  // 支持多行输入:每个非空行独立解析并输出,用空行分隔 Lines   = line:(!("n" / "") .)* "n"? { return line.join(''); }

使用说明

  • 将上述语法粘贴至 PEG.js Online Editor 或本地构建工具;
  • 输入 (3*(5+8)) → 输出:
    39 0x27 00100111
  • 输入多行(如 42n(8*7)),需配合外部 JS 代码按行分割并逐行调用 parser.parse(),PEG.js 本身不自动处理多行——这是设计使然(专注单表达式解析),但极易扩展。

⚠️ 重要注意事项

  • text() 在 Integer 规则中不可直接使用(它返回原始匹配字符串,未去除空白),应改用捕获组(如 digits:[0-9]+)再拼接;
  • 进制转换务必使用 Number(…).toString(radix) 而非 parseInt(…, radix),后者用于解析而非格式化
  • 若需统一输出宽度(如 00100111),请用 .padStart(width, ‘0’);十六进制建议加 0x 前缀提升可读性;
  • 多行输入需在宿主 JavaScript 中实现:input.split(‘n’).filter(line => line.trim()).map(line => parser.parse(line.trim()))。

总结而言,PEG.js 的语义动作是输出定制的核心机制。无需修改生成器或引入插件,仅通过内联 JavaScript 即可实现任意结构化输出——本例展示了如何将单一数值转化为清晰、对齐、多格式的诊断友好型结果,适用于嵌入式调试、教学演示或协议解析等场景。

text=ZqhQzanResources