Replace the nested if-else branch-analysis architecture with a flat DFA model using CodeGen.emitFlat — a single DFS walk emitting each block as a C label followed by its code and gotos to all successors. Removed: - _branchDescendants / emitBranch / generateCallWithError - _generateCallWithError, _noWalkNext, _genVisited - generateNextCode, findBackEdges - WCDecision._branchDescendants / _emitBranch / overridden generateCode Added: - CodeGen.emitFlat(entry) — flat DFS emit with labels + gotos - WCBlock.generateFlowCode() — base emits gotos from wcNextFlow - WCDecision.generateFlowCode() — if-goto / goto for decisions - WCProcCall.generateFlowCode() — if (call != 0) goto err / goto ok Output is flat — zero nested if-else for branch/error handling. Tests use local out/ directory.
92 lines
2.9 KiB
JavaScript
92 lines
2.9 KiB
JavaScript
// ── Pure C code generation — zero-DOM, flat DFA model ─────────────────
|
|
//
|
|
// Every block is a C label. Every flow edge is a `goto label;`.
|
|
// There is zero nesting: no if/else chains, no branch-analysis, no
|
|
// shared-block computation. Decisions become `if (cond) goto yes;
|
|
// goto no;`. Error handling becomes `if (call != 0) goto err;
|
|
// goto ok;`.
|
|
//
|
|
// Block interface:
|
|
// { id: string,
|
|
// generateOwnCode(): string, // C code for this one block
|
|
// generateFlowCode?(): string, // flow-control (gotos). If absent,
|
|
// // CodeGen walks wcNextFlow instead.
|
|
// wcNextFlow?: [{toElement: block}],
|
|
// nextFlow?: [{toElement: block}] }
|
|
|
|
(function () {
|
|
"use strict";
|
|
|
|
var CodeGen = {};
|
|
|
|
/**
|
|
* Emits a complete C program as a flat sequence of labelled blocks
|
|
* connected by gotos. Each block is emitted once (DFS order); already-
|
|
* visited blocks become `goto label;` stubs.
|
|
*
|
|
* @param {Object} entry the first block (e.g. START)
|
|
* @returns {string}
|
|
*/
|
|
CodeGen.emitFlat = function (entry) {
|
|
var visited = new Set();
|
|
var parts = [];
|
|
|
|
function emit(block) {
|
|
if (visited.has(block)) {
|
|
parts.push(" goto " + block.id + ";\n");
|
|
return;
|
|
}
|
|
visited.add(block);
|
|
parts.push("\n" + block.id + ":");
|
|
|
|
var own = block.generateOwnCode();
|
|
if (own) parts.push(own);
|
|
|
|
// Flow control: custom generateFlowCode, or auto from wcNextFlow
|
|
var flow = block.wcNextFlow || block.nextFlow || [];
|
|
var fc = "";
|
|
if (typeof block.generateFlowCode === "function") {
|
|
fc = block.generateFlowCode();
|
|
} else {
|
|
for (var i = 0; i < flow.length; i++) {
|
|
var t = flow[i].toElement;
|
|
if (t) fc += " goto " + t.id + ";\n";
|
|
}
|
|
}
|
|
if (fc) parts.push("\n" + fc);
|
|
|
|
// Recurse into successors (visited blocks are skipped at top)
|
|
for (var i = 0; i < flow.length; i++) {
|
|
var t = flow[i].toElement;
|
|
if (t) emit(t);
|
|
}
|
|
}
|
|
|
|
emit(entry);
|
|
return parts.join("");
|
|
};
|
|
|
|
/**
|
|
* Assembles a complete C source file.
|
|
*/
|
|
CodeGen.generateCFile = function (entryBlock, includes, declarations) {
|
|
var lines = ["// --- WiseCode\u00ae ---"];
|
|
for (var i = 0; i < includes.length; i++) lines.push(includes[i]);
|
|
lines.push("");
|
|
lines.push("int main() {");
|
|
if (declarations) lines.push(declarations);
|
|
lines.push(CodeGen.emitFlat(entryBlock));
|
|
lines.push("}");
|
|
lines.push("// --- END ---");
|
|
return lines.join("\n");
|
|
};
|
|
|
|
// ── Export ──────────────────────────────────────────────────────────
|
|
if (typeof module !== "undefined" && module.exports) {
|
|
module.exports = CodeGen;
|
|
}
|
|
if (typeof window !== "undefined") {
|
|
window.CodeGen = CodeGen;
|
|
}
|
|
})();
|