#!/usr/bin/env python3 """v4tof18.py -- turn the nucleus's .v4 sources into the system's .f18 blobs. v4/tools/v4tof18.py Run once (MACHINE.md step 2; plan Task 8): reads v4/capsule/*.v4 and writes capsules/v4/sys/*.f18. Everything is kept token for token and line for line except `header NAME flags :`, which text.c lays down itself and the ROM's language says with its directives: set HDR-NFA here ", NAME #, F #, HDR-NFA #, HDR-LINK set HDR-LINK here : -- the name as a counted string, the flags (immediate 1, data 4, inline 8, compile-only 16), the name's address and the link to the header before; HDR-LINK is then the new entry's code address, as text.c's latest is. The first file begins `set HDR-LINK 0`. The tokens are found as text.c's next_token finds them: `\\` and `(` as whole tokens begin comments; a header's name is the next run of characters, whatever they are. """ import os import sys ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) SRC = os.path.join(ROOT, "v4", "capsule") OUT = os.path.join(ROOT, "capsules", "v4", "sys") FILES = ["core", "input", "dict", "codegen", "compile", "quit", "forth", "numout", "words", "system", "qmath", "blocks", "log", "acl"] FLAGS = {"immediate": 1, "data": 4, "inline": 8, "compile-only": 16} BLANK = " \t\r\n" def tokens(text): """(token, start, end) for each token text.c's next_token would return, and for each header its raw name.""" i, n = 0, len(text) raw_next = False while True: while i < n and text[i] in BLANK: i += 1 if i >= n: return j = i while j < n and text[j] not in BLANK: j += 1 tok = text[i:j] if raw_next: raw_next = False yield tok, i, j i = j continue if tok == "\\": while j < n and text[j] != "\n": j += 1 i = j continue if tok == "(": k = text.find(")", j) if k < 0: sys.exit("comment not closed") i = k + 1 continue yield tok, i, j if tok == "header": raw_next = True i = j def convert(text, first): out, last = [], 0 toks = list(tokens(text)) k = 0 while k < len(toks): tok, s, e = toks[k] if tok != "header": k += 1 continue name = toks[k + 1][0] flags, m = 0, k + 2 while toks[m][0] != ":": if toks[m][0] not in FLAGS: sys.exit("header %s: %s is not a flag" % (name, toks[m][0])) flags |= FLAGS[toks[m][0]] m += 1 colon = toks[m][1] span = text[s:colon] directive = ('set HDR-NFA here ", %s #, %d #, HDR-NFA #, HDR-LINK set HDR-LINK here ' % (name, flags)) out.append(text[last:s]) out.append(directive + "\n" * span.count("\n")) last = colon k = m out.append(text[last:]) body = "".join(out) if first: body = "set HDR-LINK 0 \\ the newest dictionary entry: none yet\n" + body return body def main(): os.makedirs(OUT, exist_ok=True) for i, f in enumerate(FILES): with open(os.path.join(SRC, f + ".v4")) as h: text = h.read() with open(os.path.join(OUT, f + ".f18"), "w") as h: h.write(convert(text, i == 0)) print("v4tof18: %d files -> %s" % (len(FILES), OUT)) if __name__ == "__main__": main()