From 71e35f1320404fec01c7ef6b28b17fb74bb62a47 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Sat, 9 Oct 2021 22:41:00 +0200 Subject: [PATCH 1/3] Add `ref` operation the ref operation pushes a pointer to the variable that is currently on the top of the stack. (Only works in compilation mode, but it sould be trivial to implement it in simulation mode if real pointers are used for `mem` after the bootstrapping.) --- porth.py | 18 ++++++++++++++---- std/std.porth | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/porth.py b/porth.py index 212dfbcc..51165f79 100755 --- a/porth.py +++ b/porth.py @@ -56,6 +56,7 @@ class Intrinsic(Enum): OVER=auto() ROT=auto() MEM=auto() + REF=auto() LOAD=auto() STORE=auto() FORTH_LOAD=auto() @@ -201,7 +202,7 @@ def simulate_little_endian_linux(program: Program, argv: List[str]): else: ip += 1 elif op.typ == OpType.INTRINSIC: - assert len(Intrinsic) == 41, "Exhaustive handling of intrinsic in simulate_little_endian_linux()" + assert len(Intrinsic) == 42, "Exhaustive handling of intrinsic in simulate_little_endian_linux()" if op.operand == Intrinsic.PLUS: a = stack.pop() b = stack.pop() @@ -314,6 +315,8 @@ def simulate_little_endian_linux(program: Program, argv: List[str]): elif op.operand == Intrinsic.MEM: stack.append(mem_buf_ptr) ip += 1 + elif op.operand == Intrinsic.REF: + assert False, "%s:%d:%d Stack pointers are not allowed in simulation mode." % op.token.loc elif op.operand == Intrinsic.LOAD: addr = stack.pop() byte = mem[addr] @@ -538,7 +541,7 @@ def type_check_program(program: Program): stack.append((DataType.INT, op.token)) stack.append((DataType.PTR, op.token)) elif op.typ == OpType.INTRINSIC: - assert len(Intrinsic) == 41, "Exhaustive intrinsic handling in type_check_program()" + assert len(Intrinsic) == 42, "Exhaustive intrinsic handling in type_check_program()" assert isinstance(op.operand, Intrinsic), "This could be a bug in compilation step" if op.operand == Intrinsic.PLUS: assert len(DataType) == 3, "Exhaustive type handling in PLUS intrinsic" @@ -802,6 +805,8 @@ def type_check_program(program: Program): stack.append(c) elif op.operand == Intrinsic.MEM: stack.append((DataType.PTR, op.token)) + elif op.operand == Intrinsic.REF: + stack.append((DataType.PTR, op.token)) elif op.operand == Intrinsic.LOAD: assert len(DataType) == 3, "Exhaustive type handling in LOAD intrinsic" if len(stack) < 1: @@ -1122,7 +1127,7 @@ def generate_nasm_linux_x86_64(program: Program, out_file_path: str): assert isinstance(op.operand, int), "This could be a bug in the compilation step" out.write(" jz addr_%d\n" % op.operand) elif op.typ == OpType.INTRINSIC: - assert len(Intrinsic) == 41, "Exhaustive intrinsic handling in generate_nasm_linux_x86_64()" + assert len(Intrinsic) == 42, "Exhaustive intrinsic handling in generate_nasm_linux_x86_64()" if op.operand == Intrinsic.PLUS: out.write(" ;; -- plus --\n") out.write(" pop rax\n") @@ -1268,6 +1273,10 @@ def generate_nasm_linux_x86_64(program: Program, out_file_path: str): elif op.operand == Intrinsic.MEM: out.write(" ;; -- mem --\n") out.write(" push mem\n") + elif op.operand == Intrinsic.REF: + out.write(" ;; -- ref --\n") + out.write(" mov rax, rsp\n") + out.write(" push rax\n") elif op.operand == Intrinsic.LOAD: out.write(" ;; -- load --\n") out.write(" pop rax\n") @@ -1415,7 +1424,7 @@ def generate_nasm_linux_x86_64(program: Program, out_file_path: str): 'include': Keyword.INCLUDE, } -assert len(Intrinsic) == 41, "Exhaustive INTRINSIC_BY_NAMES definition" +assert len(Intrinsic) == 42, "Exhaustive INTRINSIC_BY_NAMES definition" INTRINSIC_BY_NAMES = { '+': Intrinsic.PLUS, '-': Intrinsic.MINUS, @@ -1439,6 +1448,7 @@ def generate_nasm_linux_x86_64(program: Program, out_file_path: str): 'over': Intrinsic.OVER, 'rot': Intrinsic.ROT, 'mem': Intrinsic.MEM, + 'ref': Intrinsic.REF, '.': Intrinsic.STORE, ',': Intrinsic.LOAD, '!': Intrinsic.FORTH_STORE, diff --git a/std/std.porth b/std/std.porth index 87f73757..753f75f8 100644 --- a/std/std.porth +++ b/std/std.porth @@ -387,6 +387,35 @@ macro puts stdout write drop end +macro putd +// a 32-byte buffer on the stack + +0 swap // a pretty awkward way to bubble up the value +0 swap +0 swap +0 swap + + dup 0 = if + "0" puts + else + ref 8 + 32 + + while over 0 > do + 1 - dup rot + 10 divmod + rot swap '0' + . swap + end + dup + ref 24 + 32 + swap - swap puts + end + drop + +// free the buffer +drop +drop +drop +drop +end + macro eputs stderr write drop end From ed534a2d3f4515d5dcf1a8e73247b261034b15cc Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Sat, 9 Oct 2021 23:05:41 +0200 Subject: [PATCH 2/3] Document the operation --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 2f9c45f7..d0ed9251 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,12 @@ push(~a) ``` push(mem_addr) ``` +- `ref` - pushes the address of the top of the stack onto the stack. (Compilation-only) +``` +# This is not actually implemented in simulation mode +push(byref(stack[-1])) +``` + - `.` - store a given byte at the address on the stack. ``` byte = pop() From 25b32d8998a618aea28729733b9e51ddef1b12f1 Mon Sep 17 00:00:00 2001 From: Andrea Piseri Date: Sat, 9 Oct 2021 23:06:09 +0200 Subject: [PATCH 3/3] cleanup --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d0ed9251..d58cf093 100644 --- a/README.md +++ b/README.md @@ -323,7 +323,6 @@ push(mem_addr) # This is not actually implemented in simulation mode push(byref(stack[-1])) ``` - - `.` - store a given byte at the address on the stack. ``` byte = pop()