2024-11-30 00:50:32 +08:00

269 lines
8.6 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/* eslint-disable no-console */
/* eslint-disable indent */
'use strict';
const fs = require('fs');
const cp = require('child_process');
const llparse = require('llparse');
const objection = lut => arg => arg.split(/\s+/).reduce((res, key) => {
if (lut[key] === undefined) {
throw new Error(key);
}
res[key] = lut[key];
return res;
}, {});
const properties = {
command: 'i8',
type: 'i8',
size: 'i32',
time: 'i64', // current simulation time
trigger: 'ptr',
triee: 'ptr', // trigger event emitter
lifee: 'ptr', // life cycle event emmiter
info: 'ptr',
value: 'ptr', // value of the signal on change event
mask: 'ptr', // mask (x, z) of the signal on change event
digitCount: 'i32',
maskCount: 'i32',
tmpStr: 'ptr',
timeStampStr: 'ptr',
idStr: 'ptr',
tmpStr2: 'ptr',
stackPointer: 'i32',
id: 'ptr',
napi_env: 'ptr'
};
const spaces = [' ', '\n', '\r', '\t'];
const lineSpaces = [' ', '\t'];
function main() {
const projectName = 'vcd_parser';
// 有关左推解析器框架 llparse 的文章移步我之前的博客https://kirigaya.cn/blog/article?seq=223
// 如果需要可视化项目图,可以取消下面的注释
// const { Dot } = require('llparse-dot');
// const llDot = new Dot();
// const dotCodeString = llDot.build(method);
// fs.writeFileSync(projectName + '.dot', code, { encoding: 'utf-8' });
// 项目名为 vcd_parser
const p = new llparse.LLParse(projectName);
// 注册一些属性
for (const propertyName of Object.keys(properties)) {
const propertyType = properties[propertyName];
p.property(propertyType, propertyName);
}
// 自定义 code span对于游走到这些 span 后要如何处理,都在 vcd_span.c 文件里
// 比如对于 varNameSpan 的定义,在 vcd_span.c 中存在一个同名的函数来定义它
const varSizeSpan = p.span(p.code.span('varSizeSpan'));
const varIdSpan = p.span(p.code.span('varIdSpan'));
const varNameSpan = p.span(p.code.span('varNameSpan'));
const idSpan = p.span(p.code.span('idSpan'));
const commandSpan = p.span(p.code.span('commandSpan'));
const timeSpan = p.span(p.code.span('timeSpan'));
// 自定义 node, 他们都是具体的节点
const declaration = p.node('declaration');
const varType = p.node('varType');
const varTypeEnd = p.node('varTypeEnd');
const varSize = p.node('varSize');
const varSizeEnd = p.node('varSizeEnd');
const varId = p.node('varId');
const varIdEnd = p.node('varIdEnd');
const varName = p.node('varName');
const varNameEnd = p.node('varNameEnd');
const inDeclaration = p.node('inDeclaration');
const simulation = p.node('simulation');
const inSimulation = p.node('inSimulation');
const simulationTime = p.node('simulationTime');
const simulationVector = p.node('simulationVector');
const simulationVectorEnd = p.node('simulationVectorEnd');
const simulationVectorRecovery = p.node('simulationVectorRecovery');
const simulationId = p.node('simulationId');
const enddefinitions = p.node('inDeclarationEnd');
// scopeType scopeTypeEnd
// scopeIdentifier scopeIdentifierEnd
const cmd = objection({
$comment: 1,
$date: 2,
$scope: 3,
$timescale: 4,
$upscope: 5,
$var: 6,
$version: 7,
$enddefinitions: 8,
$dumpall: 9,
$dumpoff: 10,
$dumpon: 11,
$dumpvars: 12,
'#': 13,
'0': 14,
'1': 15,
x: 16, X: 17,
z: 18, Z: 19,
u: 20, U: 21, // VHDL states
w: 22, W: 23,
l: 24, L: 25,
h: 26, H: 27,
'-': 28,
b: 30, B: 31, r: 32, R: 33
});
// p.code.store('command') 的具体执行逻辑移步 command-handler.js 中的 commandHandler
declaration
.match(spaces, declaration)
.select(cmd('$scope $var $upscope $comment $date $timescale $version #'),
p.invoke(p.code.store('command'), commandSpan.start(inDeclaration)))
.select(cmd('$enddefinitions'),
p.invoke(p.code.store('command'), commandSpan.start(enddefinitions)))
.otherwise(p.error(1, 'Expected declaration command'));
varType.match(spaces, varType).otherwise(varTypeEnd);
varTypeEnd
.select({
event: 1,
integer: 2,
parameter: 3,
real: 4,
realtime: 5,
reg: 6,
supply0: 7,
supply1: 8,
time: 9,
tri: 10,
triand: 11,
trior: 12,
trireg: 13,
tri0: 14,
tri1: 15,
wand: 16,
wire: 17,
wor: 18
}, p.invoke(p.code.store('type'), varSize))
.otherwise(p.error(3, 'Expected var type'));
// $var reg 3 ( r_reg [2:0] $end
// ^
varSize.match(spaces, varSize).otherwise(varSizeSpan.start(varSizeEnd));
varSizeEnd.match(spaces, varSizeSpan.end(varId)).skipTo(varSizeEnd);
// $var reg 3 ( r_reg [2:0] $end
// ^
varId.match(spaces, varId).otherwise(varIdSpan.start(varIdEnd));
varIdEnd.match(spaces, varIdSpan.end(varName)).skipTo(varIdEnd);
// $var reg 3 ( r_reg [2:0] $end
// ^^^^^
varName.match(spaces, varName).otherwise(varNameSpan.start(varNameEnd));
varNameEnd.match('$end', commandSpan.end(varNameSpan.end(declaration))).skipTo(varNameEnd);
// $end
inDeclaration
.match('$end', commandSpan.end(declaration))
.skipTo(inDeclaration);
enddefinitions
.match('$end', commandSpan.end(simulation))
.skipTo(enddefinitions);
simulation
.match([' ', '\r', '\n', '\t', '$dumpvars', '$dumpall', '$end'], simulation)
.select(cmd('$dumpoff $dumpon $comment'),
p.invoke(p.code.store('command'), commandSpan.start(inSimulation)))
.select(cmd('#'),
p.invoke(p.code.store('command'), timeSpan.start(simulationTime)))
.select(cmd('0 1 x X z Z u U w W l L h H -'),
p.invoke(p.code.store('command'), idSpan.start(simulationId)))
.select(cmd('b B r R'),
p.invoke(p.code.store('command'), simulationVector))
.otherwise(p.error(4, 'Expected simulation command'));
inSimulation
.match('$end', commandSpan.end(simulation))
.skipTo(inSimulation);
simulationTime
.match(spaces, timeSpan.end(p.invoke(p.code.span('onTime'), simulation)))
.skipTo(simulationTime);
simulationVector
.select(
{
0: 0,
1: 1,
x: 2, X: 2,
z: 3, Z: 3,
u: 3, U: 3, // VHDL states
w: 3, W: 3,
l: 3, L: 3,
h: 3, H: 3,
'-': 3
},
p.invoke(
// p.code.mulAdd('value', {base: 2, signed: false}),
p.code.value('onDigit'),
{ 1: p.error(5, 'Content-Length overflow') },
simulationVector
)
)
.otherwise(simulationVectorEnd);
simulationVectorEnd
.match(lineSpaces, idSpan.start(simulationId))
.skipTo(simulationVectorRecovery);
simulationVectorRecovery
.select(
{
'\n': 1, '\r': 1
},
p.invoke(
p.code.value('onRecover'),
{ 1: p.error(6, 'recover') },
simulation
)
)
.skipTo(simulationVectorRecovery);
simulationId
.match(spaces, idSpan.end(p.invoke(p.code.span('onId'), simulation)))
.skipTo(simulationId);
const artifacts = p.build(declaration);
fs.writeFileSync(projectName + '.h', artifacts.header);
// fs.writeFileSync('verilog_preprocessor.bc', artifacts.bitcode);
fs.writeFileSync(projectName + '.c', artifacts.c);
// const dot = new llparseDot.Dot();
// fs.writeFileSync(projectName + '.dot', dot.build(declaration));
// 使用 binding.gyp 把生成的 c 和 h 进行编译
console.log('build');
const proc = cp.spawn('node-gyp', ['configure', 'build']);
proc.stderr.on('data', data => {
console.error(data.toString());
});
proc.on('close', () => {
console.log('done');
});
};
main();
/* eslint camelcase: 0 */