Download Game! Currently 63 players and visitors. Last logged in:ZamkatVihaanSloppyZenick

Blitzer's Blog >> 71972

Back to blogs index
Posted: 03 Sep 2026 19:14 [ permalink ]
### 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?