Initial import.
This commit is contained in:
commit
3210f38e04
292 changed files with 58526 additions and 0 deletions
309
T0/kern.t0
Normal file
309
T0/kern.t0
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
: \ `\n parse drop ; immediate
|
||||
|
||||
\ This file defines the core non-native functions (mainly used for
|
||||
\ parsing words, i.e. not part of the generated output). The line above
|
||||
\ defines the syntax for comments.
|
||||
|
||||
\ Define parenthesis comments.
|
||||
\ : ( `) parse drop ; immediate
|
||||
|
||||
: else postpone ahead 1 cs-roll postpone then ; immediate
|
||||
: while postpone if 1 cs-roll ; immediate
|
||||
: repeat postpone again postpone then ; immediate
|
||||
|
||||
: ['] ' ; immediate
|
||||
: [compile] compile ; immediate
|
||||
|
||||
: 2drop drop drop ;
|
||||
: dup2 over over ;
|
||||
|
||||
\ Local variables are defined with the native word '(local)'. We define
|
||||
\ a helper construction that mimics what is found in Apple's Open Firmware
|
||||
\ implementation. The syntax is: { a b ... ; c d ... }
|
||||
\ I.e. there is an opening brace, then some names. Names appearing before
|
||||
\ the semicolon are locals that are both defined and then filled with the
|
||||
\ values on stack (in stack order: { a b } fills 'b' with the top-of-stack,
|
||||
\ and 'a' with the value immediately below). Names appearing after the
|
||||
\ semicolon are not initialized.
|
||||
: __deflocal ( from_stack name -- )
|
||||
dup (local) swap if
|
||||
compile-local-write
|
||||
else
|
||||
drop
|
||||
then ;
|
||||
: __deflocals ( from_stack -- )
|
||||
next-word
|
||||
dup "}" eqstr if
|
||||
2drop ret
|
||||
then
|
||||
dup ";" eqstr if
|
||||
2drop 0 __deflocals ret
|
||||
then
|
||||
over __deflocals
|
||||
__deflocal ;
|
||||
: {
|
||||
-1 __deflocals ; immediate
|
||||
|
||||
\ Data building words.
|
||||
: data:
|
||||
new-data-block next-word define-data-word ;
|
||||
: hexb|
|
||||
0 0 { acc z }
|
||||
begin
|
||||
char
|
||||
dup `| = if
|
||||
z if "Truncated hexadecimal byte" puts cr exitvm then
|
||||
ret
|
||||
then
|
||||
dup 0x20 > if
|
||||
hexval
|
||||
z if acc 4 << + data-add8 else >acc then
|
||||
z not >z
|
||||
then
|
||||
again ;
|
||||
|
||||
\ Convert hexadecimal character to number. Complain loudly if conversion
|
||||
\ is not possible.
|
||||
: hexval ( char -- x )
|
||||
hexval-nf dup 0 < if "Not an hex digit: " puts . cr exitvm then ;
|
||||
|
||||
\ Convert hexadecimal character to number. If not an hexadecimal digit,
|
||||
\ return -1.
|
||||
: hexval-nf ( char -- x )
|
||||
dup dup `0 >= swap `9 <= and if `0 - ret then
|
||||
dup dup `A >= swap `F <= and if `A - 10 + ret then
|
||||
dup dup `a >= swap `f <= and if `a - 10 + ret then
|
||||
drop -1 ;
|
||||
|
||||
\ Convert decimal character to number. Complain loudly if conversion
|
||||
\ is not possible.
|
||||
: decval ( char -- x )
|
||||
decval-nf dup 0 < if "Not a decimal digit: " puts . cr exitvm then ;
|
||||
|
||||
\ Convert decimal character to number. If not a decimal digit,
|
||||
\ return -1.
|
||||
: decval-nf ( char -- x )
|
||||
dup dup `0 >= swap `9 <= and if `0 - ret then
|
||||
drop -1 ;
|
||||
|
||||
\ Commonly used shorthands.
|
||||
: 1+ 1 + ;
|
||||
: 2+ 2 + ;
|
||||
: 1- 1 - ;
|
||||
: 2- 2 - ;
|
||||
: 0= 0 = ;
|
||||
: 0<> 0 <> ;
|
||||
: 0< 0 < ;
|
||||
: 0> 0 > ;
|
||||
|
||||
\ Get a 16-bit value from the constant data block. This uses big-endian
|
||||
\ encoding.
|
||||
: data-get16 ( addr -- x )
|
||||
dup data-get8 8 << swap 1+ data-get8 + ;
|
||||
|
||||
\ The case..endcase construction is the equivalent of 'switch' is C.
|
||||
\ Usage:
|
||||
\ case
|
||||
\ E1 of C1 endof
|
||||
\ E2 of C2 endof
|
||||
\ ...
|
||||
\ CN
|
||||
\ endcase
|
||||
\
|
||||
\ Upon entry, it considers the TOS (let's call it X). It will then evaluate
|
||||
\ E1, which should yield a single value Y1; at that point, the X value is
|
||||
\ still on the stack, just below Y1, and must remain untouched. The 'of'
|
||||
\ word compares X with Y1; if they are equal, C1 is executed, and then
|
||||
\ control jumps to after the 'endcase'. The X value is popped from the
|
||||
\ stack immediately before evaluating C1.
|
||||
\
|
||||
\ If X and Y1 are not equal, flow proceeds to E2, to obtain a value Y2 to
|
||||
\ compare with X. And so on.
|
||||
\
|
||||
\ If none of the 'of' clauses found a match, then CN is evaluated. When CN
|
||||
\ is evaluated, the X value is on the TOS, and CN must either leave it on
|
||||
\ the stack, or replace it with exactly one value; the 'endcase' word
|
||||
\ expects (and drops) one value.
|
||||
\
|
||||
\ Implementation: this is mostly copied from ANS Forth specification,
|
||||
\ although simplified a bit because we know that our control-flow stack
|
||||
\ is independent of the data stack. During compilation, the number of
|
||||
\ clauses is maintained on the stack; each of..endof clause really is
|
||||
\ an 'if..else' that must be terminated with a matching 'then' in 'endcase'.
|
||||
|
||||
: case 0 ; immediate
|
||||
: of 1+ postpone over postpone = postpone if postpone drop ; immediate
|
||||
: endof postpone else ; immediate
|
||||
: endcase
|
||||
postpone drop
|
||||
begin dup while 1- postpone then repeat drop ; immediate
|
||||
|
||||
\ A simpler and more generic "case": there is no management for a value
|
||||
\ on the stack, and each test is supposed to come up with its own boolean
|
||||
\ value.
|
||||
: choice 0 ; immediate
|
||||
: uf 1+ postpone if ; immediate
|
||||
: ufnot 1+ postpone ifnot ; immediate
|
||||
: enduf postpone else ; immediate
|
||||
: endchoice begin dup while 1- postpone then repeat drop ; immediate
|
||||
|
||||
\ C implementations for native words that can be used in generated code.
|
||||
add-cc: co { T0_CO(); }
|
||||
add-cc: execute { T0_ENTER(ip, rp, T0_POP()); }
|
||||
add-cc: drop { (void)T0_POP(); }
|
||||
add-cc: dup { T0_PUSH(T0_PEEK(0)); }
|
||||
add-cc: swap { T0_SWAP(); }
|
||||
add-cc: over { T0_PUSH(T0_PEEK(1)); }
|
||||
add-cc: rot { T0_ROT(); }
|
||||
add-cc: -rot { T0_NROT(); }
|
||||
add-cc: roll { T0_ROLL(T0_POP()); }
|
||||
add-cc: pick { T0_PICK(T0_POP()); }
|
||||
add-cc: + {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a + b);
|
||||
}
|
||||
add-cc: - {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a - b);
|
||||
}
|
||||
add-cc: neg {
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-a);
|
||||
}
|
||||
add-cc: * {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a * b);
|
||||
}
|
||||
add-cc: / {
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSHi(a / b);
|
||||
}
|
||||
add-cc: u/ {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a / b);
|
||||
}
|
||||
add-cc: % {
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSHi(a % b);
|
||||
}
|
||||
add-cc: u% {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a % b);
|
||||
}
|
||||
add-cc: < {
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a < b));
|
||||
}
|
||||
add-cc: <= {
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a <= b));
|
||||
}
|
||||
add-cc: > {
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a > b));
|
||||
}
|
||||
add-cc: >= {
|
||||
int32_t b = T0_POPi();
|
||||
int32_t a = T0_POPi();
|
||||
T0_PUSH(-(uint32_t)(a >= b));
|
||||
}
|
||||
add-cc: = {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a == b));
|
||||
}
|
||||
add-cc: <> {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a != b));
|
||||
}
|
||||
add-cc: u< {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a < b));
|
||||
}
|
||||
add-cc: u<= {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a <= b));
|
||||
}
|
||||
add-cc: u> {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a > b));
|
||||
}
|
||||
add-cc: u>= {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(-(uint32_t)(a >= b));
|
||||
}
|
||||
add-cc: and {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a & b);
|
||||
}
|
||||
add-cc: or {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a | b);
|
||||
}
|
||||
add-cc: xor {
|
||||
uint32_t b = T0_POP();
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(a ^ b);
|
||||
}
|
||||
add-cc: not {
|
||||
uint32_t a = T0_POP();
|
||||
T0_PUSH(~a);
|
||||
}
|
||||
add-cc: << {
|
||||
int c = (int)T0_POPi();
|
||||
uint32_t x = T0_POP();
|
||||
T0_PUSH(x << c);
|
||||
}
|
||||
add-cc: >> {
|
||||
int c = (int)T0_POPi();
|
||||
int32_t x = T0_POPi();
|
||||
T0_PUSHi(x >> c);
|
||||
}
|
||||
add-cc: u>> {
|
||||
int c = (int)T0_POPi();
|
||||
uint32_t x = T0_POP();
|
||||
T0_PUSH(x >> c);
|
||||
}
|
||||
add-cc: data-get8 {
|
||||
size_t addr = T0_POP();
|
||||
T0_PUSH(t0_datablock[addr]);
|
||||
}
|
||||
|
||||
add-cc: . {
|
||||
extern int printf(const char *fmt, ...);
|
||||
printf(" %ld", (long)T0_POPi());
|
||||
}
|
||||
add-cc: putc {
|
||||
extern int printf(const char *fmt, ...);
|
||||
printf("%c", (char)T0_POPi());
|
||||
}
|
||||
add-cc: puts {
|
||||
extern int printf(const char *fmt, ...);
|
||||
printf("%s", &t0_datablock[T0_POPi()]);
|
||||
}
|
||||
add-cc: cr {
|
||||
extern int printf(const char *fmt, ...);
|
||||
printf("\n");
|
||||
}
|
||||
add-cc: eqstr {
|
||||
const void *b = &t0_datablock[T0_POPi()];
|
||||
const void *a = &t0_datablock[T0_POPi()];
|
||||
T0_PUSH(-(int32_t)(strcmp(a, b) == 0));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue