[Joypy-announce] joypy/Joypy: Make a version for GNU Prolog compiler.

Back to archive index
scmno****@osdn***** scmno****@osdn*****
Sun Aug 11 04:19:55 JST 2019


changeset ec075de4ce6c in joypy/Joypy
details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=ec075de4ce6c
user: Simon Forman <sform****@hushm*****>
date: Sat Aug 10 12:19:09 2019 -0700
description: Make a version for GNU Prolog compiler.

diffstat:

 thun/gnu-prolog/Makefile       |    8 +
 thun/gnu-prolog/build.sh       |    1 +
 thun/gnu-prolog/compiler.pl    |  681 +++++++++++++++++++++++++++++++++++++++++
 thun/gnu-prolog/defs.txt       |   71 ++++
 thun/gnu-prolog/foo.pl         |  107 ++++++
 thun/gnu-prolog/gthun.pl       |  120 +++++++
 thun/gnu-prolog/meta.pl        |   10 +
 thun/gnu-prolog/metalogical.pl |   84 +++++
 thun/gnu-prolog/thun.pl        |  350 +++++++++++++++++++++
 thun/gnu-prolog/util.pl        |   37 ++
 10 files changed, 1469 insertions(+), 0 deletions(-)

diffs (truncated from 1512 to 300 lines):

diff -r bb69faf33d10 -r ec075de4ce6c thun/gnu-prolog/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thun/gnu-prolog/Makefile	Sat Aug 10 12:19:09 2019 -0700
@@ -0,0 +1,8 @@
+
+
+thun: thun.pl
+	gplc -o thun thun.pl
+
+foo: foo.pl
+	gplc -o foo foo.pl
+
diff -r bb69faf33d10 -r ec075de4ce6c thun/gnu-prolog/build.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thun/gnu-prolog/build.sh	Sat Aug 10 12:19:09 2019 -0700
@@ -0,0 +1,1 @@
+gplc --min-size -o thun thun.pl util.pl
diff -r bb69faf33d10 -r ec075de4ce6c thun/gnu-prolog/compiler.pl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/thun/gnu-prolog/compiler.pl	Sat Aug 10 12:19:09 2019 -0700
@@ -0,0 +1,681 @@
+/*
+
+Copyright © 2018-2019 Simon Forman
+
+This file is part of Thun
+
+Thun is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Thun is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Thun.  If not see <http://www.gnu.org/licenses/>.
+
+The Joy interpreter that this implements is pretty crude.  the only types
+are 16-bit integers and linked lists.  The lists are 32-bit words divided
+into two 16-bit fields.  The high half is the node value and the low half
+points directly (not offset) to the next cell, zero terminates the list.
+
+The expression is expected to be already written in RAM as a linked list at
+the time the mainloop starts.  As yet there is no support for actually doing
+this.  Both the new stack and expression cells are written to the same heap
+intermixed.  The stack and expression pointers never decrease, the whole
+history of the computation is recorded in RAM.  If the computation of the
+expression overruns the end of RAM (or 16-bits whichever comes first) the
+machine crashes.
+
+At the moment, functions are recognized by setting high bit, but I don't
+think I remembered to set the bits during compilation, so it won't work
+at all right now.  Er...  Boo.  Anyhow, the whole thing is very crude and
+not at all what I am hoping eventually to build.
+
+But it's a start, and I feel good about emitting machine code (even if the
+program doesn't do anything useful yet.)
+
+*/
+:- use_module(library(assoc)).
+:- use_module(library(clpfd)).
+
+
+do :- Program = [
+    ヲ,∅,⟴,ヵ,メ,ョ,
+    [グ,ケ,ゲ,ド,ゴ,サ],ヮ(cons),
+    [ザ,シ],ヮ(dup),
+    [グ,ス,[],[ジ,ス,[ズ,セ,ス,[ゼ,ソ],[タ,ゾ],ヰ,ヂ],ヱ],ヰ,チ],ヮ(i),
+    [ヶ,ペ],ワ(new),
+    [ナ,ズ,セ,ネ,ヒ,ド,ャ,ペ],ワ(swap),
+    [new,cons],≡(unit),
+    [dup,i],≡(x),
+    [swap,cons],≡(swons)
+    ],
+compile_program(Program, Binary),
+write_binary('joy_asm.bin', Binary).
+
+
+compile_program(Program, Binary) :-
+    phrase((init, ⦾(Program, IR)), [], [Context]),
+    phrase(⟐(IR), ASM),
+    phrase(linker(ASM), EnumeratedASM),
+    foo(Context),
+    phrase(asm(EnumeratedASM), Binary).
+
+foo(Context) :-
+    get_assoc(dictionary, Context, D),
+    assoc_to_list(D, Dictionary),
+    portray_clause(Dictionary).
+
+
+/*
+
+This first stage ⦾//2 converts the Joy description into a kind of intermediate
+representation that models the Joy interpreter on top of the machine but doesn't
+actually use assembly instructions.  It also manages the named registers and
+memory locations so thet don't appear in the program.
+
+The idea here is to extract the low-level "primitives" needed to define the Joy
+interpreter to make it easier to think about (and maybe eventually retarget other
+CPUs.)
+
+ */
+
+⦾([], []) --> [].
+
+⦾([ヲ|Terms], Ts) -->  % Preamble.
+    % Initialize context/state/symbol table.
+    set(dict_ptr, 11),  % Reg 11 is a pointer used during func lookup.
+    set(dict_top, 12),  % Reg 12 points to top of dictionary.
+    set(dict, 0),  % Address of top of dict during compilation.
+    set(done, _DONE),  % DONE label (logic variable.)
+    set(expr, 4),  % Reg 4 points to expression.
+    set(halt, _HALT),  % HALT label (logic variable.)
+    set(main, _MAIN),  % MAIN label (logic variable.)
+    set(reset, _Reset),  % Reset label (logic variable.)
+    set(sp, 2),  % Reg 2 points to just under top of stack.
+    set(temp0, 6),  % Reg 6 is a temp var.
+    set(temp1, 7),  % Reg 7 is a temp var.
+    set(temp2, 8),  % Reg 8 is a temp var.
+    set(temp3, 9),  % Reg 9 is a temp var.
+    set(term, 5),  % Reg 4 holds current term.
+    set(tos, 3),  % Reg 3 holds Top of Stack.
+    ⦾(Terms, Ts).
+
+⦾([ヵ|Terms], [  % Initialization.
+    jump(Over),  % Oberon bootloader writes MemLim to RAM[12] and
+    asm(allocate(_, 16)),  % stackOrg to RAM[24], we don't need these
+    label(Over),  % but they must not be allowed to corrupt our code.
+    set_reg_const(0, 0),  % zero out the root cell.
+    write_ram(0, 0),
+    set_reg_const(SP, 0x1000),
+    set_reg_const(EXPR, 0x500),
+    set_reg_label(DICT_TOP, LastWord),
+    set_reg_const(TOS, 0),
+    set_reg_const(TERM, 0),
+    asm(store_word(TOS, SP, 0))  % RAM[SP] := 0
+    |Ts]) -->
+    get([dict_top, DICT_TOP, expr, EXPR, sp, SP, term, TERM, tos, TOS]),
+    ⦾(Terms, Ts), get(dict, LastWord).
+
+⦾([メ|Terms], [  % Mainloop.
+    label(MAIN),
+    if_zero(EXPR, HALT),
+    deref(EXPR),
+    split_word(TERM, EXPR),
+    if_literal(TERM, PUSH),
+    lookup(DICT_PTR, DICT_TOP, TERM, HALT),  % Jump to command or if not found halt.
+    label(PUSH), push(TOS, TERM, SP),  % stack = TERM, stack
+    label(DONE), write_ram(SP, TOS),   % RAM[SP] := TOS
+    jump(MAIN)
+    |Ts]) -->
+    get([dict_ptr, DICT_PTR, dict_top, DICT_TOP, done, DONE, expr, EXPR,
+         halt, HALT, main, MAIN, sp, SP, term, TERM, tos, TOS]),
+    ⦾(Terms, Ts).
+
+⦾([Body, ≡(NameAtom)|Terms], [defi(Name, B, Prev, I, SP, TOS)|Ts]) -->
+    get(dict, Prev), set(dict, Name), get([sp, SP, tos, TOS]),
+    inscribe(NameAtom, Name), ⦾(Terms, Ts), lookup(i, I), lookup(Body, B).
+
+⦾([Body, ヮ(NameAtom)|Terms], [definition(Name, DONE, B, Prev)|Ts]) -->
+    get(dict, Prev), set(dict, Name), inscribe(NameAtom, Name),
+    get(done, DONE), ⦾([Body, Terms], [B, Ts]).
+
+⦾([Body, ワ(NameAtom)|Terms], [definition(Name, MAIN, B, Prev)|Ts]) -->
+    get(dict, Prev), set(dict, Name), inscribe(NameAtom, Name),
+    get(main, MAIN), ⦾([Body, Terms], [B, Ts]).
+
+⦾([P, T, E, ヰ|Terms], [br(Predicate, Then, Else)|Ts]) -->
+    ⦾([P, T, E, Terms], [Predicate, Then, Else, Ts]).
+
+⦾([P, B, ヱ|Terms], [repeat_until(Predicate, Body)|Ts]) -->
+    ⦾([P, B, Terms], [Predicate, Body, Ts]).
+
+⦾([Term|Terms], [T|Ts]) --> ⦾(Term, T), ⦾(Terms, Ts).
+
+⦾(∅, dw(0))                    --> [].
+⦾(⟴, label(Reset))             --> get(reset, Reset).
+⦾(ョ, halt(HALT))               --> get(halt, HALT).
+⦾(グ, pop(TEMP0, TOS))          --> get(temp0, TEMP0), get(tos, TOS).
+⦾(シ, push(TOS, TOS, SP))       --> get(tos, TOS), get(sp, SP).
+⦾(ケ, high_half(TEMP1, TOS))    --> get(temp1, TEMP1), get(tos, TOS).
+⦾(サ, merge(SP, TOS))           --> get(tos, TOS), get(sp, SP).
+⦾(ザ, swap_halves(TOS))         --> get(tos, TOS).
+⦾(ズ, deref(TEMP0))             --> get(temp0, TEMP0).
+⦾(ス, if_zero(TEMP0))           --> get(temp0, TEMP0).
+⦾(ソ, asm(mov(EXPR, TEMP3)))    --> get(expr, EXPR), get(temp3, TEMP3).
+⦾(ャ, asm(ior(TOS, TEMP1, SP))) --> get(tos, TOS), get(temp1, TEMP1), get(sp, SP).
+⦾(タ, add_const(TEMP2, SP, 8))  --> get(temp2, TEMP2), get(sp, SP).
+⦾(ジ, add_const(TEMP3, SP, 4))  --> get(temp3, TEMP3), get(sp, SP).
+⦾(チ, add_const(SP, SP, 4))     --> get(sp, SP).
+⦾(セ, chop_word(TEMP1, TEMP0))  --> get(temp0, TEMP0), get(temp1, TEMP1).
+⦾(ト, chop_word(TEMP0, TOS))    --> get(temp0, TEMP0), get(tos, TOS).
+⦾(ネ, chop_word(TEMP2, TOS))    --> get(temp2, TEMP2), get(tos, TOS).
+⦾(ゼ, or_inplace(TEMP1,  EXPR)) --> get(expr, EXPR), get(temp1, TEMP1).
+⦾(ゲ, or_inplace(TEMP0, TEMP1)) --> get(temp0, TEMP0), get(temp1, TEMP1).
+⦾(ヒ, or_inplace(TEMP0, TEMP2)) --> get(temp0, TEMP0), get(temp2, TEMP2).
+⦾(ゾ, or_inplace(TEMP1, TEMP2)) --> get(temp1, TEMP1), get(temp2, TEMP2).
+⦾(ド, write_cell(TEMP0, SP))    --> get(temp0, TEMP0), get(sp, SP).
+⦾(ヂ, write_cell(TEMP1, SP))    --> get(temp1, TEMP1), get(sp, SP).
+⦾(ペ, write_cell(TOS,   SP))    --> get(tos, TOS), get(sp, SP).
+⦾(ゴ, low_half(TOS))            --> get(tos, TOS).
+⦾(ナ, low_half(TEMP0, TOS))     --> get(temp0, TEMP0), get(tos, TOS).
+⦾(ヶ, low_half(TOS, SP))        --> get(sp, SP), get(tos, TOS).
+
+
+/* 
+
+Context (state) manipulation for the ⦾//2 relation.
+
+Association lists are used to keep a kind of symbol table as well as a dictionary
+of name atoms to address logic variables for defined Joy functions.
+
+*/
+
+init, [Context] -->
+    {empty_assoc(C), empty_assoc(Dictionary),
+     put_assoc(dictionary, C, Dictionary, Context)}.
+
+get([]) --> !.
+get([Key, Value|Ts]) --> !, get(Key, Value), get(Ts).
+
+get(Key, Value) --> state(Context), {get_assoc(Key, Context, Value)}.
+set(Key, Value) --> state(ContextIn, ContextOut),
+    {put_assoc(Key, ContextIn, Value, ContextOut)}.
+
+inscribe(NameAtom, Label) --> state(ContextIn, ContextOut),
+    {get_assoc(dictionary, ContextIn, Din),
+     put_assoc(NameAtom, Din, Label, Dout),
+     put_assoc(dictionary, ContextIn, Dout, ContextOut)}.
+
+lookup([], []) --> !.
+lookup([T|Ts], [V|Vs]) --> !, lookup(T, V), lookup(Ts, Vs).
+lookup(NameAtom, Label) --> state(Context),
+    {get_assoc(dictionary, Context, D), get_assoc(NameAtom, D, Label)}.
+
+state(S), [S] --> [S].
+state(S0, S), [S] --> [S0].
+
+
+/*
+
+This second stage ⟐//1 converts the intermediate representation to assembly
+language.
+
+*/
+
+⟐([]) --> [].
+⟐([Term|Terms]) --> ⟐(Term), ⟐(Terms).
+
+⟐(if_literal(Reg, Label)) -->  %  commands marked by setting high bit.
+    [and_imm(0, Reg, 0x8000),  % 1 << 15
+     eq_offset(Label)].
+
+% if reg = 0 jump to label.
+⟐(if_zero(Reg, Label)) --> [sub_imm(Reg, Reg, 0), eq_offset(Label)].
+
+⟐(set_reg_const(Reg, Immediate)) --> {Immediate >= -(2^15), Immediate < 2^16}, !,
+    [mov_imm(Reg, Immediate)].
+
+⟐(set_reg_const(Reg, Immediate)) --> {Immediate >= 0, Immediate < 2^33}, !,  % FIXME: handle negative numbers.
+    {high_half_word(Immediate, HighHalf), low_half_word(Immediate,  LowHalf)},
+    [  mov_imm_with_shift(Reg, HighHalf),         ior_imm(Reg, Reg, LowHalf)].
+
+⟐(set_reg_label(Reg, Label)) --> [mov_imm(Reg, Label)].
+
+⟐(        noop) --> [mov(0, 0)].
+⟐(  halt(Halt)) --> [label(Halt), do_offset(Halt)].
+⟐(    asm(ASM)) --> [ASM].
+⟐(label(Label)) --> [label(Label)].
+⟐( jump(Label)) --> [do_offset(Label)].
+⟐(     dw(Int)) --> [word(Int)].
+
+⟐(      low_half(Reg)) --> [and_imm(Reg, Reg, 0xffff)].
+⟐( low_half(To, From)) --> [and_imm(To, From, 0xffff)].
+⟐(     high_half(Reg)) --> [mov_imm_with_shift(0, 0xffff), and(Reg, Reg, 0)].
+⟐(high_half(To, From)) --> [mov_imm_with_shift(0, 0xffff), and(To, From, 0)].
+
+⟐(swap_halves(Register)) --> [ror_imm(Register, Register, 16)].
+⟐(swap_halves(To, From)) --> [ror_imm(      To,     From, 16)].
+
+⟐(high_half_to(To, From)) --> ⟐([swap_halves(To, From), low_half(To)]).
+
+⟐(split_word(To, From)) --> ⟐([high_half_to(To, From), low_half(From)]).
+
+⟐(chop_word(To, From)) --> ⟐([high_half(To, From), low_half(From)]).
+
+⟐(merge(SP, TOS)) -->
+    [lsl_imm(0, SP, 16),
+     ior(TOS, TOS, 0),
+     add_imm(SP, SP, 4)].
+
+⟐(push(TOS, TERM, SP)) -->
+    [lsl_imm(TOS, TERM, 16),  %  TOS := TERM << 16
+     ior(TOS, TOS, SP),       %  TOS := TOS | SP
+     add_imm(SP, SP, 4)].     % SP += 1 (word, not byte)
+


More information about the Joypy-announce mailing list
Back to archive index