### Writing the Literal Extractor (JS Port)
To make our JS compiler generate the exact `gd_allocate_vars` block you
provided, we need to port `unliteralize_data`, `add_literal`, and the unique
ID generator.
Here is the implementation to add to our `GDCompiler` class:
```javascript
class GDCompiler {
constructor() {
this.reset();
}
reset() {
this.uniq_id_cnt = 0;
this.tmp_variables = new Map(); // Stores literal mapping
tokens
this.tmp_variables_by_literal = new Map(); // For deduplication
this.c_comment = 0;
this.line_num = 0;
// ... other state vars
}
uniq_id(base = "") {
return `${base}${this.uniq_id_cnt++}`;
}
add_literal(value, type, ref_token = null) {
// Check if we already have this exact literal
if (this.tmp_variables_by_literal.has(value)) {
return this.tmp_variables_by_literal.get(value).variable_name;
}
const indice = this.uniq_id(`_tmp_${type}`);
const token = {
type: "variable",
source: value,
variable_type: type,
variable_name: indice,
resolved_type: type,
// Assuming default line/col from ref_token if provided
line_num: ref_token ? ref_token.line_num : this.line_num,
column_num: ref_token ? ref_token.column_num : 0
};
this.tmp_variables.set(indice, token);
// all_variables.set(indice, token); // We'll need this map later for
full resolution
this.tmp_variables_by_literal.set(value, token);
return indice;
}
unliteralize_data(buf) {
let quote_on = -1;
let quote_tick = 0;
let quoted = "";
let ret_buf = "";
for (let pos = 0; pos < buf.length; pos++) {
let c = buf[pos];
// C-style comment block skipping
if (this.c_comment) {
if (c === '*' && buf[pos + 1] === '/') {
this.c_comment = 0;
pos++;
}
continue;
}
if (quote_on === -1) {
if (c === '/' && buf[pos + 1] === '*') {
this.c_comment = this.line_num + 1;
pos++;
continue;
} else if (c === '"') {
quote_on = pos;
} else if (c === "'") {
quote_on = pos;
quote_tick = 1;
} else {
ret_buf += c;
}
} else if (quote_tick === 0) { // Inside a double-quote string
if (c === '"') {
// Reached end of string, replace with literal reference
ret_buf += this.add_literal(`"${quoted}"`, "string");
quote_on = -1;
quoted = "";
} else if (c === '\\') {
quoted += c;
pos++;
quoted += buf[pos];
} else {
quoted += c;
}
} else { // Inside a single-quote character
if (c === "'") {
// Reached end of char, replace with literal reference
ret_buf += this.add_literal(`'${quoted}'`, "char");
quote_on = -1;
quote_tick = 0;
quoted = "";
} else if (c === '\\') {
quoted += c;
pos++;
quoted += buf[pos];
} else {
quoted += c;
}
}
}
return ret_buf;
}
}
```
### Next Step Integration
If you run `tests/string.c` through this `unliteralize_data` JS function, it
will strip out every `"` and `'` wrapped string, map them sequentially
(`_tmp_string0` to `_tmp_string31`), and leave the raw code behind.
Shall we plug this into the test harness to verify it correctly outputs the
`tmp_variables` map, or would you prefer to port the `scan_number` utility
next so we can extract the `_tmp_int32` to `_tmp_int40` values exactly as the
C binary does?