duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit ba8c097f27fee341fcf288eb722ae5095b0481fe
parent 5383af43de8b81fffff7d995cf8a13ac9cdf4dc8
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Tue, 29 Nov 2022 22:13:37 -0500

comp/c: add support for the "x ? y : z" operators

Diffstat:
Mfs/ar/puff.c | 8+++-----
Mfs/comp/c/pgen.fs | 12++++++++----
Mfs/comp/c/vm/forth.fs | 8++++++++
Mfs/comp/c/vm/i386.fs | 6++++++
Mfs/doc/cc/impl.txt | 22++++++++++++++++++++++
Mfs/tests/comp/c/cc.fs | 2++
Mfs/tests/comp/c/test.c | 3+++
7 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/fs/ar/puff.c b/fs/ar/puff.c @@ -388,11 +388,8 @@ static int codes(state *s, huffman *lencode, huffman *distcode) if (s->outcnt + len > s->outlen) return 1; while (len--) { - // TODO: add "cond ? x : y" form - if (dist > s->outcnt) - s->out[s->outcnt] = 0; - else - s->out[s->outcnt] = s->out[s->outcnt - dist]; + s->out[s->outcnt] = dist > s->outcnt ? + 0 : s->out[s->outcnt - dist]; s->outcnt++; } } @@ -711,6 +708,7 @@ int puff(unsigned char *dest, /* pointer to destination pointer */ do { last = bits(&s, 1); /* one if last block */ type = bits(&s, 2); /* block type 0..3 */ + // TODO: the ?: ops fail on this if (type == 0) err = stored(&s); else if (type == 1) err = fixed(&s); else if (type == 2) err = dynamic(&s); diff --git a/fs/comp/c/pgen.fs b/fs/comp/c/pgen.fs @@ -53,15 +53,19 @@ POPSCNT wordtbl popgentbl ( -- ) : poptoken ( opid -- tok ) POPTlist slistiter ; \ Binary operators -29 const BOPSCNT +31 const BOPSCNT BOPSCNT stringlist BOPTlist "+" "-" "*" "/" "%" "<<" ">>" "<" ">" "<=" ">=" "==" "!=" "&" "^" "|" - "&&" "||" "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>=" "&=" "^=" "|=" + "&&" "||" "=" "+=" "-=" "*=" "/=" "%=" "<<=" ">>=" "&=" "^=" "|=" "?" ":" \ binary ops precedence. lower means more precedence create bopsprectbl BOPSCNT nc, 1 1 0 0 0 2 2 3 3 3 3 4 4 5 5 5 - 6 6 7 7 7 7 7 7 7 7 7 7 7 + 6 6 7 7 7 7 7 7 7 7 7 7 7 8 9 + +MAXARGCNT Stack :new structbind Stack _stack?: +: _? vmop :push _stack?: :push selop^ ; +: _: _stack?: :pop vm?:, ; BOPSCNT wordtbl bopgentbl ( -- ) 'w vm+, 'w vm-, 'w vm*, 'w vm/, @@ -71,7 +75,7 @@ BOPSCNT wordtbl bopgentbl ( -- ) 'w vm&&, 'w vm||, 'w vm=, 'w vm+=, 'w vm-=, 'w vm*=, 'w vm/=, 'w vm%=, 'w vm<<=, 'w vm>>=, 'w vm&=, 'w vm^=, -'w vm|=, +'w vm|=, 'w _? 'w _: : bopid ( tok -- opid? f ) BOPTlist sfind dup 0< if drop 0 else 1 then ; diff --git a/fs/comp/c/vm/forth.fs b/fs/comp/c/vm/forth.fs @@ -161,3 +161,11 @@ LOGOPCNT wordtbl _tblunsigned : vmjz[, ( -- a ) _ [compile] if ; : vmjnz, ( a -- ) _ compile not [compile] until ; : vmjnz[, ( -- a ) _ compile not [compile] if ; + +: vm?:, ( condop -- ) + vmop^ :compile$ \ false-res on TOS + vmop^ :pop vmop^ :compile$ [compile] if PS- + \ we're in the "true" branch. drop the false res, replace with true. + compile drop PS- vmop :compile$ + ]vmjmp vmop :>reg ; + diff --git a/fs/comp/c/vm/i386.fs b/fs/comp/c/vm/i386.fs @@ -293,3 +293,9 @@ LOGOPCNT wordtbl _tblunsigned : vmjz[, ( -- a ) vmtest, forward jz, ; : vmjnz, ( a -- ) vmtest, abs>rel jnz, ; : vmjnz[, ( -- a ) vmtest, forward jnz, ; + +: vm?:, ( condop -- ) + vmop :>res \ true op in reg + vmop :push swap vmop :pop vmjnz[, swap vmop :pop \ vmop back to its res + vmop :compile vmop^ :compile mov, vmop^ :init \ move false op to true reg + ]vmjmp ; diff --git a/fs/doc/cc/impl.txt b/fs/doc/cc/impl.txt @@ -158,6 +158,27 @@ Assign op: Same as Binary op. vmret,: Requires a deallocated vmop^. If vmop is allocated, compile a push to PS and then de-allocate it. +### vm?:, ( condop -- ) + +(I intend to have a more complete documentation of the different operation +types, but for now I just want to document this tricky little op while it's +fresh.) + +Now that's a special little op, a triop masquerading as a binop. The idea is +that we do a little bit like a if() *except* that it leaks a value, something +that the regular if() doesn't do (this has implication for the Forth VM which +tracks PS levels). + +You call this op at the ":" operator. When you encountered the "?" operator, you +simply :push'ed your operand and kept it around, and kept vmop^ (the "result if +true" operand) as vmop. Now, at ":" time, you have your true op in vmop and your +false one in vmop^. + +Calling vm?:, will compile both ops, wraping them around jumps, but, more +importantly, it will "merge" vmop and vmop^ into one single op, that is, the +location that *both* branches of the condition will return to. That will be the +result of this binop. This "merge" is arch-specific. + ### Jumping in the VM There are 2 kinds of jumps: forward and backward. In forward jumps, we need to @@ -177,3 +198,4 @@ Backward jumps are written with the non-"[" words: here ... vmjmp, here ... vmjnz, + diff --git a/fs/tests/comp/c/cc.fs b/fs/tests/comp/c/cc.fs @@ -16,6 +16,8 @@ binopshl 336 #eq binopshr 10 #eq binopdiv 14 #eq binopmod 1 #eq +1 binopcondeval 42 #eq +0 binopcondeval 12 #eq assignops 83 #eq boolops 0 #eq funcall 42 #eq diff --git a/fs/tests/comp/c/test.c b/fs/tests/comp/c/test.c @@ -52,6 +52,9 @@ int binopmod() { int a=43; return a % 3; } +int binopcondeval(int x) { + return x ? 42 : 12 ; +} int assignops() { int a=42, b=2, c=3; a += b; // 44