Initial import.

This commit is contained in:
Thomas Pornin 2016-11-02 19:01:13 -04:00
commit 3210f38e04
292 changed files with 58526 additions and 0 deletions

112
T0/BlobWriter.cs Normal file
View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.IO;
using System.Text;
/*
* A simple class for writing out bytes as hexadecimal constants or
* explicit expressions for the initializer of a C array of 'unsigned
* char'. It starts every line with a given number of tabs, and aims at
* keeping lines below a given threshold (each indentation tab counts as
* 8 characters). An explicit newline is inserted before the first
* element, and commas are used as separators.
*/
class BlobWriter {
TextWriter w;
int maxLineLen;
int indent;
int lineLen;
/*
* Create a new instance. 'maxLineLen' is in characters, and
* 'indent' is the number of tab characters at the start of
* each line.
*/
internal BlobWriter(TextWriter w, int maxLineLen, int indent)
{
this.w = w;
this.maxLineLen = maxLineLen;
this.indent = indent;
lineLen = -1;
}
void DoNL()
{
w.WriteLine();
for (int i = 0; i < indent; i ++) {
w.Write('\t');
}
lineLen = (indent << 3);
}
/*
* Append a new byte value; it will be converted to an hexadecimal
* constant in the output.
*/
internal void Append(byte b)
{
if (lineLen < 0) {
DoNL();
} else {
w.Write(',');
lineLen ++;
if ((lineLen + 5) > maxLineLen) {
DoNL();
} else {
w.Write(' ');
lineLen ++;
}
}
w.Write("0x{0:X2}", b);
lineLen += 4;
}
/*
* Append a C expression, which will be used as is. The expression
* may resolve to several bytes if it uses internal commas. The
* writer will try to honour the expected line length, but it
* won't insert a newline character inside the expression.
*/
internal void Append(string expr)
{
if (lineLen < 0) {
DoNL();
} else {
w.Write(',');
lineLen ++;
if ((lineLen + 1 + expr.Length) > maxLineLen) {
DoNL();
} else {
w.Write(' ');
lineLen ++;
}
}
w.Write("{0}", expr);
lineLen += expr.Length;
}
}

181
T0/CPU.cs Normal file
View file

@ -0,0 +1,181 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
/*
* Execution of code during compilation is done in a virtual CPU
* incarnated by this class, that contains the relevant registers.
*
* Accesses to the data on the stack are mapped to accesses to an
* internal array, with no explicit control on boundaries. Since the
* internal array may be larger than the actual stack contents,
* nonsensical accesses may still "work" to some extent. The whole
* thing won't derail beyond the CLR VM, though.
*/
class CPU {
/*
* Next instruction to execute is in ipBuf[ipOff].
*/
internal Opcode[] ipBuf;
internal int ipOff;
/*
* stackBuf and stackPtr implement the data stack. The system
* stack uses frames; 'rsp' points to the current top frame.
*/
TValue[] stackBuf;
int stackPtr;
Frame rsp;
internal CPU()
{
stackBuf = new TValue[16];
stackPtr = -1;
rsp = null;
}
/*
* Enter a function, reserving space for 'numLocals' local variables.
*/
internal void Enter(Opcode[] code, int numLocals)
{
Frame f = new Frame(rsp, numLocals);
rsp = f;
f.savedIpBuf = ipBuf;
f.savedIpOff = ipOff;
ipBuf = code;
ipOff = 0;
}
/*
* Exit the current function.
*/
internal void Exit()
{
ipBuf = rsp.savedIpBuf;
ipOff = rsp.savedIpOff;
rsp = rsp.upper;
}
/*
* Get the current stack depth (number of elements).
*/
internal int Depth {
get {
return stackPtr + 1;
}
}
/*
* Pop a value from the stack.
*/
internal TValue Pop()
{
return stackBuf[stackPtr --];
}
/*
* Push a value on the stack.
*/
internal void Push(TValue v)
{
int len = stackBuf.Length;
if (++ stackPtr == len) {
TValue[] nbuf = new TValue[len << 1];
Array.Copy(stackBuf, 0, nbuf, 0, len);
stackBuf = nbuf;
}
stackBuf[stackPtr] = v;
}
/*
* Look at the value at depth 'depth' (0 is top of stack). The
* stack is unchanged.
*/
internal TValue Peek(int depth)
{
return stackBuf[stackPtr - depth];
}
/*
* Rotate the stack at depth 'depth': the value at that depth
* is moved to the top of stack.
*/
internal void Rot(int depth)
{
TValue v = stackBuf[stackPtr - depth];
Array.Copy(stackBuf, stackPtr - (depth - 1),
stackBuf, stackPtr - depth, depth);
stackBuf[stackPtr] = v;
}
/*
* Inverse-rotate the stack at depth 'depth': the value at the
* top of stack is moved to that depth.
*/
internal void NRot(int depth)
{
TValue v = stackBuf[stackPtr];
Array.Copy(stackBuf, stackPtr - depth,
stackBuf, stackPtr - (depth - 1), depth);
stackBuf[stackPtr - depth] = v;
}
/*
* Get the current contents of the local variable 'num'.
*/
internal TValue GetLocal(int num)
{
return rsp.locals[num];
}
/*
* Set the contents of the local variable 'num'.
*/
internal void PutLocal(int num, TValue v)
{
rsp.locals[num] = v;
}
/*
* The system stack really is a linked list of Frame instances.
*/
class Frame {
internal Frame upper;
internal Opcode[] savedIpBuf;
internal int savedIpOff;
internal TValue[] locals;
internal Frame(Frame upper, int numLocals)
{
this.upper = upper;
locals = new TValue[numLocals];
}
}
}

88
T0/CodeElement.cs Normal file
View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
abstract class CodeElement {
internal int Address { get; set; }
internal int LastLength { get; set; }
internal abstract int Length { get; }
internal CodeElement()
{
Address = -1;
}
internal virtual void SetJumpTarget(CodeElement target)
{
throw new Exception("Code element accepts no target");
}
internal abstract int Encode(BlobWriter bw);
internal static int Encode7EUnsigned(uint val, BlobWriter bw)
{
int len = 1;
for (uint w = val; w >= 0x80; w >>= 7) {
len ++;
}
if (bw != null) {
for (int k = (len - 1) * 7; k >= 0; k -= 7) {
int x = (int)(val >> k) & 0x7F;
if (k > 0) {
x |= 0x80;
}
bw.Append((byte)x);
}
}
return len;
}
internal static int Encode7ESigned(int val, BlobWriter bw)
{
int len = 1;
if (val < 0) {
for (int w = val; w < -0x40; w >>= 7) {
len ++;
}
} else {
for (int w = val; w >= 0x40; w >>= 7) {
len ++;
}
}
if (bw != null) {
for (int k = (len - 1) * 7; k >= 0; k -= 7) {
int x = (int)(val >> k) & 0x7F;
if (k > 0) {
x |= 0x80;
}
bw.Append((byte)x);
}
}
return len;
}
}

78
T0/CodeElementJump.cs Normal file
View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
class CodeElementJump : CodeElement {
uint jumpType;
CodeElement target;
internal CodeElementJump(uint jumpType)
{
this.jumpType = jumpType;
}
internal override int Length {
get {
int len = Encode7EUnsigned(jumpType, null);
int joff = JumpOff;
if (joff == Int32.MinValue) {
len ++;
} else {
len += Encode7ESigned(joff, null);
}
return len;
}
}
internal override void SetJumpTarget(CodeElement target)
{
this.target = target;
}
int JumpOff {
get {
if (target == null || Address < 0 || target.Address < 0)
{
return Int32.MinValue;
} else {
return target.Address - (Address + LastLength);
}
}
}
internal override int Encode(BlobWriter bw)
{
if (bw == null) {
return Length;
}
int len = Encode7EUnsigned(jumpType, bw);
int joff = JumpOff;
if (joff == Int32.MinValue) {
throw new Exception("Unresolved addresses");
}
return len + Encode7ESigned(joff, bw);
}
}

46
T0/CodeElementUInt.cs Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
class CodeElementUInt : CodeElement {
uint val;
internal CodeElementUInt(uint val) : base()
{
this.val = val;
}
internal override int Length {
get {
return Encode7EUnsigned(val, null);
}
}
internal override int Encode(BlobWriter bw)
{
return Encode7EUnsigned(val, bw);
}
}

56
T0/CodeElementUIntExpr.cs Normal file
View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
class CodeElementUIntExpr : CodeElement {
uint val;
TPointerExpr cx;
int off;
internal CodeElementUIntExpr(uint val,
TPointerExpr cx, int off) : base()
{
this.val = val;
this.cx = cx;
this.off = off;
}
internal override int Length {
get {
return Encode7EUnsigned(val, null)
+ (cx.GetMaxBitLength(off) + 6) / 7;
}
}
internal override int Encode(BlobWriter bw)
{
int len1 = Encode7EUnsigned(val, bw);
int len2 = (cx.GetMaxBitLength(off) + 6) / 7;
bw.Append(String.Format("T0_INT{0}({1})",
len2, cx.ToCExpr(off)));
return len1 + len2;
}
}

51
T0/CodeElementUIntInt.cs Normal file
View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
class CodeElementUIntInt : CodeElement {
uint val1;
int val2;
internal CodeElementUIntInt(uint val1, int val2) : base()
{
this.val1 = val1;
this.val2 = val2;
}
internal override int Length {
get {
return Encode7EUnsigned(val1, null)
+ Encode7ESigned(val2, null);
}
}
internal override int Encode(BlobWriter bw)
{
int len = Encode7EUnsigned(val1, bw);
len += Encode7ESigned(val2, bw);
return len;
}
}

50
T0/CodeElementUIntUInt.cs Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
class CodeElementUIntUInt : CodeElement {
uint val1, val2;
internal CodeElementUIntUInt(uint val1, uint val2) : base()
{
this.val1 = val1;
this.val2 = val2;
}
internal override int Length {
get {
return Encode7EUnsigned(val1, null)
+ Encode7EUnsigned(val2, null);
}
}
internal override int Encode(BlobWriter bw)
{
int len = Encode7EUnsigned(val1, bw);
len += Encode7EUnsigned(val2, bw);
return len;
}
}

198
T0/ConstData.cs Normal file
View file

@ -0,0 +1,198 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
class ConstData {
internal long ID { get; private set; }
internal int Address { get; set; }
internal int Length {
get {
return len;
}
}
byte[] buf;
int len;
internal ConstData(T0Comp ctx)
{
ID = ctx.NextBlobID();
buf = new byte[4];
len = 0;
}
void Expand(int elen)
{
int tlen = len + elen;
if (tlen > buf.Length) {
int nlen = Math.Max(buf.Length << 1, tlen);
byte[] nbuf = new byte[nlen];
Array.Copy(buf, 0, nbuf, 0, len);
buf = nbuf;
}
}
internal void Add8(byte b)
{
Expand(1);
buf[len ++] = b;
}
internal void Add16(int x)
{
Expand(2);
buf[len ++] = (byte)(x >> 8);
buf[len ++] = (byte)x;
}
internal void Add24(int x)
{
Expand(3);
buf[len ++] = (byte)(x >> 16);
buf[len ++] = (byte)(x >> 8);
buf[len ++] = (byte)x;
}
internal void Add32(int x)
{
Expand(4);
buf[len ++] = (byte)(x >> 24);
buf[len ++] = (byte)(x >> 16);
buf[len ++] = (byte)(x >> 8);
buf[len ++] = (byte)x;
}
internal void AddString(string s)
{
byte[] sd = Encoding.UTF8.GetBytes(s);
Expand(sd.Length + 1);
Array.Copy(sd, 0, buf, len, sd.Length);
buf[len + sd.Length] = 0;
len += sd.Length + 1;
}
void CheckIndex(int off, int dlen)
{
if (off < 0 || off > (len - dlen)) {
throw new IndexOutOfRangeException();
}
}
internal void Set8(int off, byte v)
{
CheckIndex(off, 1);
buf[off] = v;
}
internal byte Read8(int off)
{
CheckIndex(off, 1);
return buf[off];
}
internal int Read16(int off)
{
CheckIndex(off, 2);
return (buf[off] << 8) | buf[off + 1];
}
internal int Read24(int off)
{
CheckIndex(off, 3);
return (buf[off] << 16) | (buf[off + 1] << 8) | buf[off + 2];
}
internal int Read32(int off)
{
CheckIndex(off, 4);
return (buf[off] << 24) | (buf[off + 1] << 16)
| (buf[off + 2] << 8) | buf[off + 3];
}
internal string ToString(int off)
{
StringBuilder sb = new StringBuilder();
for (;;) {
int x = DecodeUTF8(ref off);
if (x == 0) {
return sb.ToString();
}
if (x < 0x10000) {
sb.Append((char)x);
} else {
x -= 0x10000;
sb.Append((char)(0xD800 + (x >> 10)));
sb.Append((char)(0xDC00 + (x & 0x3FF)));
}
}
}
int DecodeUTF8(ref int off)
{
if (off >= len) {
throw new IndexOutOfRangeException();
}
int x = buf[off ++];
if (x < 0xC0 || x > 0xF7) {
return x;
}
int elen, acc;
if (x >= 0xF0) {
elen = 3;
acc = x & 0x07;
} else if (x >= 0xE0) {
elen = 2;
acc = x & 0x0F;
} else {
elen = 1;
acc = x & 0x1F;
}
if (off + elen > len) {
return x;
}
for (int i = 0; i < elen; i ++) {
int y = buf[off + i];
if (y < 0x80 || y >= 0xC0) {
return x;
}
acc = (acc << 6) + (y & 0x3F);
}
if (acc > 0x10FFFF) {
return x;
}
off += elen;
return acc;
}
internal void Encode(BlobWriter bw)
{
for (int i = 0; i < len; i ++) {
bw.Append(buf[i]);
}
}
}

117
T0/Opcode.cs Normal file
View file

@ -0,0 +1,117 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
abstract class Opcode {
internal Opcode()
{
}
/*
* Execute this opcode.
*/
internal abstract void Run(CPU cpu);
/*
* Resolve the target (word reference) for this opcode.
*/
internal virtual void ResolveTarget(Word target)
{
throw new Exception("Not a call opcode");
}
/*
* Resolve the jump offset for this opcode. Displacement is
* relative to the address of the opcode that immediately follows
* the jump code; thus, 0 implies no jump at all.
*/
internal virtual void ResolveJump(int disp)
{
throw new Exception("Not a jump opcode");
}
/*
* Get the Word that this opcode references; this can happen
* only with "call" and "const" opcodes. For all other opcodes,
* this method returns null.
*/
internal virtual Word GetReference(T0Comp ctx)
{
return null;
}
/*
* Get the data block that this opcode references; this can happen
* only with "const" opcodes. For all other opcodes, this method
* returns null.
*/
internal virtual ConstData GetDataBlock(T0Comp ctx)
{
return null;
}
/*
* Test whether this opcode may "fall through", i.e. execution
* may at least potentially proceed to the next opcode.
*/
internal virtual bool MayFallThrough {
get {
return true;
}
}
/*
* Get jump displacement. For non-jump opcodes, this returns 0.
*/
internal virtual int JumpDisp {
get {
return 0;
}
}
/*
* Get stack effect for this opcode (number of elements added to
* the stack, could be negative). For OpcodeCall, this returns
* 0.
*/
internal virtual int StackAction {
get {
return 0;
}
}
internal abstract CodeElement ToCodeElement();
/*
* This method is called for the CodeElement corresponding to
* this opcode, at gcode[off]; it is used to compute actual
* byte jump offsets when converting code to C.
*/
internal virtual void FixUp(CodeElement[] gcode, int off)
{
}
}

71
T0/OpcodeCall.cs Normal file
View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeCall : Opcode {
Word target;
internal OpcodeCall() : this(null)
{
}
internal OpcodeCall(Word target)
{
this.target = target;
}
internal override void ResolveTarget(Word target)
{
if (this.target != null) {
throw new Exception("Opcode already resolved");
}
this.target = target;
}
internal override void Run(CPU cpu)
{
target.Run(cpu);
}
internal override Word GetReference(T0Comp ctx)
{
if (target == null) {
throw new Exception("Unresolved call target");
}
return target;
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUInt((uint)target.Slot);
}
public override string ToString()
{
return "call " + (target == null ? "UNRESOLVED" : target.Name);
}
}

95
T0/OpcodeConst.cs Normal file
View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeConst : Opcode {
TValue val;
internal OpcodeConst(TValue val)
{
this.val = val;
}
internal override void Run(CPU cpu)
{
cpu.Push(val);
}
internal override Word GetReference(T0Comp ctx)
{
TPointerXT xt = val.ptr as TPointerXT;
if (xt == null) {
return null;
}
xt.Resolve(ctx);
return xt.Target;
}
internal override ConstData GetDataBlock(T0Comp ctx)
{
TPointerBlob bp = val.ptr as TPointerBlob;
return bp == null ? null : bp.Blob;
}
internal override CodeElement ToCodeElement()
{
if (val.ptr == null) {
return new CodeElementUIntInt(1, val.Int);
}
TPointerXT xt = val.ptr as TPointerXT;
if (xt != null) {
if (val.x != 0) {
throw new Exception(
"Cannot compile XT: non-zero offset");
}
return new CodeElementUIntInt(1, xt.Target.Slot);
}
TPointerBlob bp = val.ptr as TPointerBlob;
if (bp != null) {
return new CodeElementUIntInt(1,
val.x + bp.Blob.Address);
}
TPointerExpr cx = val.ptr as TPointerExpr;
if (cx != null) {
return new CodeElementUIntExpr(1, cx, val.x);
}
throw new Exception(String.Format(
"Cannot embed constant (type = {0})",
val.ptr.GetType().FullName));
}
internal override int StackAction {
get {
return 1;
}
}
public override string ToString()
{
return "const " + val.ToString();
}
}

57
T0/OpcodeGetLocal.cs Normal file
View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeGetLocal : Opcode {
int num;
internal OpcodeGetLocal(int num)
{
this.num = num;
}
internal override void Run(CPU cpu)
{
cpu.Push(cpu.GetLocal(num));
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUIntUInt(2, (uint)num);
}
internal override int StackAction {
get {
return 1;
}
}
public override string ToString()
{
return "getlocal " + num;
}
}

64
T0/OpcodeJump.cs Normal file
View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
abstract class OpcodeJump : Opcode {
int disp;
internal OpcodeJump() : this(Int32.MinValue)
{
}
internal OpcodeJump(int disp)
{
this.disp = disp;
}
internal override int JumpDisp {
get {
return disp;
}
}
internal override void Run(CPU cpu)
{
cpu.ipOff += disp;
}
internal override void ResolveJump(int disp)
{
if (this.disp != Int32.MinValue) {
throw new Exception("Jump already resolved");
}
this.disp = disp;
}
internal override void FixUp(CodeElement[] gcode, int off)
{
gcode[off].SetJumpTarget(gcode[off + 1 + disp]);
}
}

65
T0/OpcodeJumpIf.cs Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeJumpIf : OpcodeJump {
internal OpcodeJumpIf() : base()
{
}
internal OpcodeJumpIf(int disp) : base(disp)
{
}
internal override void Run(CPU cpu)
{
TValue v = cpu.Pop();
if (v.Bool) {
base.Run(cpu);
}
}
internal override int StackAction {
get {
return -1;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementJump(5);
}
public override string ToString()
{
if (JumpDisp == Int32.MinValue) {
return "jumpif UNRESOLVED";
} else {
return "jumpif disp=" + JumpDisp;
}
}
}

65
T0/OpcodeJumpIfNot.cs Normal file
View file

@ -0,0 +1,65 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeJumpIfNot : OpcodeJump {
internal OpcodeJumpIfNot() : base()
{
}
internal OpcodeJumpIfNot(int disp) : base(disp)
{
}
internal override void Run(CPU cpu)
{
TValue v = cpu.Pop();
if (!v.Bool) {
base.Run(cpu);
}
}
internal override int StackAction {
get {
return -1;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementJump(6);
}
public override string ToString()
{
if (JumpDisp == Int32.MinValue) {
return "jumpifnot UNRESOLVED";
} else {
return "jumpifnot disp=" + JumpDisp;
}
}
}

61
T0/OpcodeJumpUncond.cs Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeJumpUncond : OpcodeJump {
internal OpcodeJumpUncond() : base()
{
}
internal OpcodeJumpUncond(int disp) : base(disp)
{
}
/*
* Unconditional jumps do not "fall through" unless they
* happen to be a jump to the next instruction...
*/
internal override bool MayFallThrough {
get {
return JumpDisp == 0;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementJump(4);
}
public override string ToString()
{
if (JumpDisp == Int32.MinValue) {
return "jump UNRESOLVED";
} else {
return "jump disp=" + JumpDisp;
}
}
}

57
T0/OpcodePutLocal.cs Normal file
View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodePutLocal : Opcode {
int num;
internal OpcodePutLocal(int num)
{
this.num = num;
}
internal override void Run(CPU cpu)
{
cpu.PutLocal(num, cpu.Pop());
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUIntUInt(3, (uint)num);
}
internal override int StackAction {
get {
return -1;
}
}
public override string ToString()
{
return "putlocal " + num;
}
}

50
T0/OpcodeRet.cs Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class OpcodeRet : Opcode {
internal override void Run(CPU cpu)
{
cpu.Exit();
}
internal override bool MayFallThrough {
get {
return false;
}
}
internal override CodeElement ToCodeElement()
{
return new CodeElementUInt(0);
}
public override string ToString()
{
return "ret";
}
}

129
T0/SType.cs Normal file
View file

@ -0,0 +1,129 @@
using System;
/*
* This structure contains the stack effect of a word: number of stack
* element consumed on input, and number of stack element produced on
* output.
*/
struct SType {
/*
* Get number of stack elements consumed on input; this is -1 if
* the stack effect is not known.
*/
internal int DataIn {
get {
return din;
}
}
/*
* Get number of stack elements produced on output; this is -1 if
* either the stack effect is not known, or if the word never
* exits.
*/
internal int DataOut {
get {
return dout;
}
}
/*
* Tell whether the stack effect is known.
*/
internal bool IsKnown {
get {
return din >= 0;
}
}
/*
* Tell whether the stack effect is known and the word never exits.
*/
internal bool NoExit {
get {
return din >= 0 && dout < 0;
}
}
int din, dout;
internal SType(int din, int dout)
{
if (din < 0) {
din = -1;
}
if (dout < 0) {
dout = -1;
}
this.din = din;
this.dout = dout;
}
/*
* Special value for the unknown stack effect.
*/
internal static SType UNKNOWN = new SType(-1, -1);
/*
* Constant for the "blank stack effect".
*/
internal static SType BLANK = new SType(0, 0);
public static bool operator ==(SType s1, SType s2)
{
return s1.din == s2.din && s1.dout == s2.dout;
}
public static bool operator !=(SType s1, SType s2)
{
return s1.din != s2.din || s1.dout != s2.dout;
}
public override bool Equals(Object obj)
{
return (obj is SType) && ((SType)obj == this);
}
public override int GetHashCode()
{
return din * 31 + dout * 17;
}
public override string ToString()
{
if (!IsKnown) {
return "UNKNOWN";
} else if (NoExit) {
return string.Format("in:{0},noexit", din);
} else {
return string.Format("in:{0},out:{1}", din, dout);
}
}
/*
* Test whether this stack effect is a sub-effect of the provided
* stack effect s. Stack effect s1 is a sub-effect of stack-effect
* s2 if any of the following holds:
* -- s1 and s2 are known, s1.din <= s2.din and s1 does not exit.
* -- s1 and s2 are known, s1.din <= s2.din, s1 and s2 exit,
* and s1.din - s1.dout == s2.din - s2.dout.
*/
internal bool IsSubOf(SType s)
{
if (!IsKnown || !s.IsKnown) {
return false;
}
if (din > s.din) {
return false;
}
if (NoExit) {
return true;
}
if (s.NoExit) {
return false;
}
return (din - dout) == (s.din - s.dout);
}
}

2070
T0/T0Comp.cs Normal file

File diff suppressed because it is too large Load diff

64
T0/TPointerBase.cs Normal file
View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class TPointerBase {
/* obsolete
internal virtual TValue Get(TValue vp)
{
throw new Exception(
"cannot get values from this pointer");
}
internal virtual void Set(TValue vp, TValue nval)
{
throw new Exception(
"cannot set values to this pointer");
}
*/
internal virtual bool ToBool(TValue vp)
{
return true;
}
internal virtual void Execute(T0Comp ctx, CPU cpu)
{
throw new Exception("value is not an xt: " + ToString());
}
internal virtual string ToString(TValue vp)
{
return String.Format("{0}+{1}",
GetType().Name, vp.x);
}
internal virtual bool Equals(TPointerBase tp)
{
return this == tp;
}
}

75
T0/TPointerBlob.cs Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class TPointerBlob : TPointerBase {
internal ConstData Blob { get; private set; }
internal TPointerBlob(ConstData cd)
{
this.Blob = cd;
}
internal TPointerBlob(T0Comp owner, string s)
{
Blob = new ConstData(owner);
Blob.AddString(s);
}
/* obsolete
internal override TValue Get8(TValue vp)
{
return new TValue((int)Blob.Read8(vp.x));
}
internal override TValue Get16(TValue vp)
{
return new TValue((int)Blob.Read16(vp.x));
}
internal override TValue Get24(TValue vp)
{
return new TValue((int)Blob.Read24(vp.x));
}
internal override TValue Get32(TValue vp)
{
return new TValue((int)Blob.Read32(vp.x));
}
*/
internal override string ToString(TValue vp)
{
return Blob.ToString(vp.x);
}
internal override bool Equals(TPointerBase tp)
{
TPointerBlob tb = tp as TPointerBlob;
return tb != null && Blob == tb.Blob;
}
}

97
T0/TPointerExpr.cs Normal file
View file

@ -0,0 +1,97 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
class TPointerExpr : TPointerBase {
string expr;
int min, max;
internal TPointerExpr(string expr, int min, int max)
{
this.expr = expr;
this.min = min;
this.max = max;
}
internal override bool ToBool(TValue vp)
{
throw new Exception("Cannot evaluate C-expr at compile time");
}
internal override string ToString(TValue vp)
{
return ToCExpr(vp.x);
}
internal string ToCExpr(int off)
{
if (off == 0) {
return expr;
} else if (off > 0) {
return String.Format(
"(uint32_t)({0}) + {1}", expr, off);
} else {
return String.Format(
"(uint32_t)({0}) - {1}", expr, -(long)off);
}
}
internal int GetMaxBitLength(int off)
{
long rmin = (long)min + off;
long rmax = (long)max + off;
int numBits = 1;
if (rmin < 0) {
numBits = Math.Max(numBits, BitLength(rmin));
}
if (rmax > 0) {
numBits = Math.Max(numBits, BitLength(rmax));
}
return Math.Min(numBits, 32);
}
/*
* Get the minimal bit length of a value. This is for a signed
* representation: the length includes a sign bit. Thus, the
* returned value will be at least 1.
*/
static int BitLength(long v)
{
int num = 1;
if (v < 0) {
while (v != -1) {
num ++;
v >>= 1;
}
} else {
while (v != 0) {
num ++;
v >>= 1;
}
}
return num;
}
}

44
T0/TPointerNull.cs Normal file
View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class TPointerNull : TPointerBase {
internal override bool ToBool(TValue vp)
{
return false;
}
internal override string ToString(TValue vp)
{
return "null";
}
internal override bool Equals(TPointerBase tp)
{
return tp is TPointerNull;
}
}

73
T0/TPointerXT.cs Normal file
View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class TPointerXT : TPointerBase {
internal string Name {
get; private set;
}
internal Word Target {
get; private set;
}
internal TPointerXT(string name)
{
this.Name = name;
this.Target = null;
}
internal TPointerXT(Word target)
{
this.Name = target.Name;
this.Target = target;
}
internal void Resolve(T0Comp ctx)
{
if (Target == null) {
Target = ctx.Lookup(Name);
}
}
internal override void Execute(T0Comp ctx, CPU cpu)
{
Resolve(ctx);
Target.Run(cpu);
}
internal override string ToString(TValue vp)
{
return String.Format("<'{0}>", Name);
}
internal override bool Equals(TPointerBase tp)
{
TPointerXT tx = tp as TPointerXT;
return tx != null && Name == tx.Name;
}
}

231
T0/TValue.cs Normal file
View file

@ -0,0 +1,231 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
/*
* Each value is represented with a TValue structure. Integers use the 'x'
* field, and 'ptr' is null; for pointers, the 'ptr' field is used, and the
* 'x' is then an offset in the object represented by 'ptr'.
*/
struct TValue {
internal int x;
internal TPointerBase ptr;
internal TValue(int x)
{
this.x = x;
this.ptr = null;
}
internal TValue(uint x)
{
this.x = (int)x;
this.ptr = null;
}
internal TValue(bool b)
{
this.x = b ? -1 : 0;
this.ptr = null;
}
internal TValue(int x, TPointerBase ptr)
{
this.x = x;
this.ptr = ptr;
}
/*
* Convert this value to a boolean; integer 0 and null pointer are
* 'false', other values are 'true'.
*/
internal bool Bool {
get {
if (ptr == null) {
return x != 0;
} else {
return ptr.ToBool(this);
}
}
}
/*
* Get this value as an integer. Pointers cannot be converted to
* integers.
*/
internal int Int {
get {
if (ptr == null) {
return x;
}
throw new Exception("not an integer: " + ToString());
}
}
/*
* Get this value as an unsigned integer. This is the integer
* value, reduced modulo 2^32 in the 0..2^32-1 range.
*/
internal uint UInt {
get {
return (uint)Int;
}
}
/*
* String format of integers uses decimal representation. For
* pointers, this depends on the pointed-to value.
*/
public override string ToString()
{
if (ptr == null) {
return String.Format("{0}", x);
} else {
return ptr.ToString(this);
}
}
/*
* If this value is an XT, then execute it. Otherwise, an exception
* is thrown.
*/
internal void Execute(T0Comp ctx, CPU cpu)
{
ToXT().Execute(ctx, cpu);
}
/*
* Convert this value to an XT. On failure, an exception is thrown.
*/
internal TPointerXT ToXT()
{
TPointerXT xt = ptr as TPointerXT;
if (xt == null) {
throw new Exception(
"value is not an xt: " + ToString());
}
return xt;
}
/*
* Compare this value to another.
*/
internal bool Equals(TValue v)
{
if (x != v.x) {
return false;
}
if (ptr == v.ptr) {
return true;
}
if (ptr == null || v.ptr == null) {
return false;
}
return ptr.Equals(v.ptr);
}
public static implicit operator TValue(bool val)
{
return new TValue(val);
}
public static implicit operator TValue(sbyte val)
{
return new TValue((int)val);
}
public static implicit operator TValue(byte val)
{
return new TValue((int)val);
}
public static implicit operator TValue(short val)
{
return new TValue((int)val);
}
public static implicit operator TValue(ushort val)
{
return new TValue((int)val);
}
public static implicit operator TValue(char val)
{
return new TValue((int)val);
}
public static implicit operator TValue(int val)
{
return new TValue((int)val);
}
public static implicit operator TValue(uint val)
{
return new TValue((int)val);
}
public static implicit operator bool(TValue v)
{
return v.Bool;
}
public static implicit operator sbyte(TValue v)
{
return (sbyte)v.Int;
}
public static implicit operator byte(TValue v)
{
return (byte)v.Int;
}
public static implicit operator short(TValue v)
{
return (short)v.Int;
}
public static implicit operator ushort(TValue v)
{
return (ushort)v.Int;
}
public static implicit operator char(TValue v)
{
return (char)v.Int;
}
public static implicit operator int(TValue v)
{
return (int)v.Int;
}
public static implicit operator uint(TValue v)
{
return (uint)v.Int;
}
}

172
T0/Word.cs Normal file
View file

@ -0,0 +1,172 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
/*
* A "word" is a function with a name. Words can be either native or
* interpreted; native words are implemented as some in-compiler special
* code.
*
* Some native words (not all of them) have a C implementation and can
* thus be part of the generated C code. Native words with no C
* implementation can be used only during compilation; this is typically
* the case for words that support the syntax (e.g. 'if').
*/
abstract class Word {
/*
* The compiler context for this word.
*/
internal T0Comp TC {
get; private set;
}
/*
* Immediate words are executed immediately when encountered in the
* source code, even while compiling another word.
*/
internal bool Immediate {
get; set;
}
/*
* Each word has a unique name. Names are case-sensitive.
*/
internal string Name {
get; private set;
}
/*
* Words are allocated slot numbers when output code is generated.
*/
internal int Slot {
get; set;
}
/*
* Each word may have a known stack effect.
*/
internal SType StackEffect {
get; set;
}
internal Word(T0Comp owner, string name)
{
TC = owner;
Name = name;
StackEffect = SType.UNKNOWN;
}
/*
* Resolving a word means looking up all references to external
* words.
*/
internal virtual void Resolve()
{
}
/*
* Execute this word. If the word is native, then its code is
* run right away; if the word is interpreted, then the entry
* sequence is executed.
*/
internal virtual void Run(CPU cpu)
{
throw new Exception(String.Format(
"cannot run '{0}' at compile-time", Name));
}
/*
* All words may have an explicit C implementations. To be part
* of the generated C code, a word must either be interpreted,
* or have an explicit C implementation, or both.
*/
internal string CCode {
get; set;
}
/*
* Get all words referenced from this one. This implies
* resolving the word.
*/
internal virtual List<Word> GetReferences()
{
return new List<Word>();
}
/*
* Get all data blocks directly referenced from this one. This
* implies resolving the word.
*/
internal virtual List<ConstData> GetDataBlocks()
{
return new List<ConstData>();
}
/*
* Produce the code elements for this word.
*/
internal virtual void GenerateCodeElements(List<CodeElement> dst)
{
throw new Exception("Word does not yield code elements");
}
/*
* Compute/verify stack effect for this word.
*/
internal virtual void AnalyseFlow()
{
}
/*
* Get maximum data stack usage for this word. This is the number
* of extra slots that this word may need on the data stack. If
* the stack effect is not known, this returns -1.
*/
internal virtual int MaxDataStack {
get {
SType se = StackEffect;
if (!se.IsKnown) {
return -1;
}
if (se.NoExit) {
return 0;
} else {
return Math.Min(0, se.DataOut - se.DataIn);
}
}
}
/*
* Get maximum return stack usage for this word.
*/
internal virtual int MaxReturnStack {
get {
return 0;
}
}
}

385
T0/WordBuilder.cs Normal file
View file

@ -0,0 +1,385 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
/*
* A WordBuilder instance organizes construction of a new interpreted word.
*
* Opcodes are accumulated with specific methods. A control-flow stack
* is maintained to resolve jumps.
*
* Each instance shall be used for only one word.
*/
class WordBuilder {
T0Comp TC;
string name;
int[] cfStack;
int cfPtr;
List<Opcode> code;
List<string> toResolve;
Dictionary<string, int> locals;
bool jumpToLast;
internal SType StackEffect {
get; set;
}
/*
* Create a new instance, with the specified word name.
*/
internal WordBuilder(T0Comp TC, string name)
{
this.TC = TC;
this.name = name;
cfStack = new int[16];
cfPtr = -1;
code = new List<Opcode>();
toResolve = new List<string>();
locals = new Dictionary<string, int>();
jumpToLast = true;
StackEffect = SType.UNKNOWN;
}
/*
* Build the word. The control-flow stack must be empty. A 'ret'
* opcode is automatically appended if required.
*/
internal Word Build()
{
if (cfPtr != -1) {
throw new Exception("control-flow stack is not empty");
}
if (jumpToLast || code[code.Count - 1].MayFallThrough) {
Ret();
}
Word w = new WordInterpreted(TC, name, locals.Count,
code.ToArray(), toResolve.ToArray());
w.StackEffect = StackEffect;
return w;
}
void Add(Opcode op)
{
Add(op, null);
}
void Add(Opcode op, string refName)
{
code.Add(op);
toResolve.Add(refName);
jumpToLast = false;
}
/*
* Rotate the control-flow stack at depth 'depth'.
*/
internal void CSRoll(int depth)
{
int x = cfStack[cfPtr - depth];
Array.Copy(cfStack, cfPtr - (depth - 1),
cfStack, cfPtr - depth, depth);
cfStack[cfPtr] = x;
}
/*
* Make a copy of the control-flow element at depth 'depth', and
* push it on top of the control-flow stack.
*/
internal void CSPick(int depth)
{
int x = cfStack[cfPtr - depth];
CSPush(x);
}
void CSPush(int x)
{
int len = cfStack.Length;
if (++ cfPtr == len) {
int[] ncf = new int[len << 1];
Array.Copy(cfStack, 0, ncf, 0, len);
cfStack = ncf;
}
cfStack[cfPtr] = x;
}
int CSPop()
{
return cfStack[cfPtr --];
}
/*
* Push an origin on the control-flow stack, corresponding to the
* next opcode to add.
*/
internal void CSPushOrig()
{
CSPush(code.Count);
}
/*
* Push a destination on the control-flow stack, corresponding to
* the next opcode to add.
*/
internal void CSPushDest()
{
CSPush(-code.Count - 1);
}
/*
* Pop an origin from the control-flow stack. An exception is
* thrown if the value is not an origin.
*/
internal int CSPopOrig()
{
int x = CSPop();
if (x < 0) {
throw new Exception("not an origin");
}
return x;
}
/*
* Pop a destination from the control-flow stack. An exception is
* thrown if the value is not a destination.
*/
internal int CSPopDest()
{
int x = CSPop();
if (x >= 0) {
throw new Exception("not a destination");
}
return -x - 1;
}
/*
* Add a "push literal" opcode.
*/
internal void Literal(TValue v)
{
Add(new OpcodeConst(v));
}
/*
* Compile a "call" by name. This method implements the support
* for local variables:
*
* - If the target is '>' followed by a local variable name, then
* a "put local" opcode is added.
*
* - Otherwise, if the target is a local variable name, then a
* "get local" opcode is added.
*
* - Otherwise, a call to the named word is added. The target name
* will be resolved later on (typically, when the word containing
* the call opcode is first invoked, or when C code is generated).
*/
internal void Call(string target)
{
string lname;
bool write;
if (target.StartsWith(">")) {
lname = target.Substring(1);
write = true;
} else {
lname = target;
write = false;
}
int lnum;
if (locals.TryGetValue(lname, out lnum)) {
if (write) {
Add(new OpcodePutLocal(lnum));
} else {
Add(new OpcodeGetLocal(lnum));
}
} else {
Add(new OpcodeCall(), target);
}
}
/*
* Add a "call" opcode to the designated word.
*/
internal void CallExt(Word wtarget)
{
Add(new OpcodeCall(wtarget), null);
}
/*
* Add a "call" opcode to a word which is not currently resolved.
* This method ignores local variables.
*/
internal void CallExt(string target)
{
Add(new OpcodeCall(), target);
}
/*
* Add a "get local" opcode; the provided local name must already
* be defined.
*/
internal void GetLocal(string name)
{
int lnum;
if (locals.TryGetValue(name, out lnum)) {
Add(new OpcodeGetLocal(lnum));
} else {
throw new Exception("no such local: " + name);
}
}
/*
* Add a "put local" opcode; the provided local name must already
* be defined.
*/
internal void PutLocal(string name)
{
int lnum;
if (locals.TryGetValue(name, out lnum)) {
Add(new OpcodePutLocal(lnum));
} else {
throw new Exception("no such local: " + name);
}
}
/*
* Define a new local name.
*/
internal void DefLocal(string lname)
{
if (locals.ContainsKey(lname)) {
throw new Exception(String.Format(
"local already defined: {0}", lname));
}
locals[lname] = locals.Count;
}
/*
* Add a "call" opcode whose target is an XT value (which may be
* resolved or as yet unresolved).
*/
internal void Call(TPointerXT xt)
{
if (xt.Target == null) {
Add(new OpcodeCall(), xt.Name);
} else {
Add(new OpcodeCall(xt.Target));
}
}
/*
* Add a "ret" opcode.
*/
internal void Ret()
{
Add(new OpcodeRet());
}
/*
* Add a forward unconditional jump. The new opcode address is
* pushed on the control-flow stack as an origin.
*/
internal void Ahead()
{
CSPushOrig();
Add(new OpcodeJumpUncond());
}
/*
* Add a forward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'true'. The new opcode address is
* pushed on the control-flow stack as an origin.
*/
internal void AheadIf()
{
CSPushOrig();
Add(new OpcodeJumpIf());
}
/*
* Add a forward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'false'. The new opcode address is
* pushed on the control-flow stack as an origin.
*/
internal void AheadIfNot()
{
CSPushOrig();
Add(new OpcodeJumpIfNot());
}
/*
* Resolve a previous forward jump to the current code address.
* The top of control-flow stack is popped and must be an origin.
*/
internal void Then()
{
int x = CSPopOrig();
code[x].ResolveJump(code.Count - x - 1);
jumpToLast = true;
}
/*
* Push the current code address on the control-flow stack as a
* destination, to be used by an ulterior backward jump.
*/
internal void Begin()
{
CSPushDest();
}
/*
* Add a backward unconditional jump. The jump target is popped
* from the control-flow stack as a destination.
*/
internal void Again()
{
int x = CSPopDest();
Add(new OpcodeJumpUncond(x - code.Count - 1));
}
/*
* Add a backward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'true'. The jump target is popped
* from the control-flow stack as a destination.
*/
internal void AgainIf()
{
int x = CSPopDest();
Add(new OpcodeJumpIf(x - code.Count - 1));
}
/*
* Add a backward conditional jump, which will be taken at runtime
* if the top-of-stack value is 'false'. The jump target is popped
* from the control-flow stack as a destination.
*/
internal void AgainIfNot()
{
int x = CSPopDest();
Add(new OpcodeJumpIfNot(x - code.Count - 1));
}
}

96
T0/WordData.cs Normal file
View file

@ -0,0 +1,96 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
class WordData : Word {
ConstData blob;
string baseBlobName;
int offset;
bool ongoingResolution;
internal WordData(T0Comp owner, string name,
ConstData blob, int offset)
: base(owner, name)
{
this.blob = blob;
this.offset = offset;
StackEffect = new SType(0, 1);
}
internal WordData(T0Comp owner, string name,
string baseBlobName, int offset)
: base(owner, name)
{
this.baseBlobName = baseBlobName;
this.offset = offset;
StackEffect = new SType(0, 1);
}
internal override void Resolve()
{
if (blob != null) {
return;
}
if (ongoingResolution) {
throw new Exception(String.Format(
"circular reference in blobs ({0})", Name));
}
ongoingResolution = true;
WordData wd = TC.Lookup(baseBlobName) as WordData;
if (wd == null) {
throw new Exception(String.Format(
"data word '{0}' based on non-data word '{1}'",
Name, baseBlobName));
}
wd.Resolve();
blob = wd.blob;
offset += wd.offset;
ongoingResolution = false;
}
internal override void Run(CPU cpu)
{
Resolve();
cpu.Push(new TValue(offset, new TPointerBlob(blob)));
}
internal override List<ConstData> GetDataBlocks()
{
Resolve();
List<ConstData> r = new List<ConstData>();
r.Add(blob);
return r;
}
internal override void GenerateCodeElements(List<CodeElement> dst)
{
Resolve();
dst.Add(new CodeElementUInt(0));
dst.Add(new CodeElementUIntInt(1, blob.Address + offset));
dst.Add(new CodeElementUInt(0));
}
}

283
T0/WordInterpreted.cs Normal file
View file

@ -0,0 +1,283 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
/*
* The implementation for interpreted words.
*/
class WordInterpreted : Word {
/*
* Get the number of local variables for this word.
*/
internal int NumLocals {
get; private set;
}
/*
* Get the sequence of opcodes for this word.
*/
internal Opcode[] Code {
get; private set;
}
string[] toResolve;
internal WordInterpreted(T0Comp owner, string name,
int numLocals, Opcode[] code, string[] toResolve)
: base(owner, name)
{
this.Code = code;
this.toResolve = toResolve;
NumLocals = numLocals;
}
internal override void Resolve()
{
if (toResolve == null) {
return;
}
for (int i = 0; i < toResolve.Length; i ++) {
string tt = toResolve[i];
if (tt == null) {
continue;
}
Code[i].ResolveTarget(TC.Lookup(tt));
}
toResolve = null;
}
internal override void Run(CPU cpu)
{
Resolve();
cpu.Enter(Code, NumLocals);
}
internal override List<Word> GetReferences()
{
Resolve();
List<Word> r = new List<Word>();
foreach (Opcode op in Code) {
Word w = op.GetReference(TC);
if (w != null) {
r.Add(w);
}
}
return r;
}
internal override List<ConstData> GetDataBlocks()
{
Resolve();
List<ConstData> r = new List<ConstData>();
foreach (Opcode op in Code) {
ConstData cd = op.GetDataBlock(TC);
if (cd != null) {
r.Add(cd);
}
}
return r;
}
internal override void GenerateCodeElements(List<CodeElement> dst)
{
Resolve();
int n = Code.Length;
CodeElement[] gcode = new CodeElement[n];
for (int i = 0; i < n; i ++) {
gcode[i] = Code[i].ToCodeElement();
}
for (int i = 0; i < n; i ++) {
Code[i].FixUp(gcode, i);
}
dst.Add(new CodeElementUInt((uint)NumLocals));
for (int i = 0; i < n; i ++) {
dst.Add(gcode[i]);
}
}
int flowAnalysis;
int maxDataStack;
int maxReturnStack;
bool MergeSA(int[] sa, int j, int c)
{
if (sa[j] == Int32.MinValue) {
sa[j] = c;
return true;
} else if (sa[j] != c) {
throw new Exception(string.Format(
"In word '{0}', offset {1}:"
+ " stack action mismatch ({2} / {3})",
Name, j, sa[j], c));
} else {
return false;
}
}
internal override void AnalyseFlow()
{
switch (flowAnalysis) {
case 0:
break;
case 1:
return;
default:
throw new Exception("recursive call detected in '"
+ Name + "'");
}
flowAnalysis = 2;
int n = Code.Length;
int[] sa = new int[n];
for (int i = 0; i < n; i ++) {
sa[i] = Int32.MinValue;
}
sa[0] = 0;
int[] toExplore = new int[n];
int tX = 0, tY = 0;
int off = 0;
int exitSA = Int32.MinValue;
int mds = 0;
int mrs = 0;
int maxDepth = 0;
for (;;) {
Opcode op = Code[off];
bool mft = op.MayFallThrough;
int c = sa[off];
int a;
if (op is OpcodeCall) {
Word w = op.GetReference(TC);
w.AnalyseFlow();
SType se = w.StackEffect;
if (!se.IsKnown) {
throw new Exception(string.Format(
"call from '{0}' to '{1}'"
+ " with unknown stack effect",
Name, w.Name));
}
if (se.NoExit) {
mft = false;
a = 0;
} else {
a = se.DataOut - se.DataIn;
}
mds = Math.Max(mds, c + w.MaxDataStack);
mrs = Math.Max(mrs, w.MaxReturnStack);
maxDepth = Math.Min(maxDepth, c - se.DataIn);
} else if (op is OpcodeRet) {
if (exitSA == Int32.MinValue) {
exitSA = c;
} else if (exitSA != c) {
throw new Exception(string.Format(
"'{0}': exit stack action"
+ " mismatch: {1} / {2}"
+ " (offset {3})",
Name, exitSA, c, off));
}
a = 0;
} else {
a = op.StackAction;
mds = Math.Max(mds, c + a);
}
c += a;
maxDepth = Math.Min(maxDepth, c);
int j = op.JumpDisp;
if (j != 0) {
j += off + 1;
toExplore[tY ++] = j;
MergeSA(sa, j, c);
}
off ++;
if (!mft || !MergeSA(sa, off, c)) {
if (tX < tY) {
off = toExplore[tX ++];
} else {
break;
}
}
}
maxDataStack = mds;
maxReturnStack = 1 + NumLocals + mrs;
/*
* TODO: see about this warning. Usage of a 'fail'
* word (that does not exit) within a 'case..endcase'
* structure will make an unreachable opcode. In a future
* version we might want to automatically remove dead
* opcodes.
for (int i = 0; i < n; i ++) {
if (sa[i] == Int32.MinValue) {
Console.WriteLine("warning: word '{0}',"
+ " offset {1}: unreachable opcode",
Name, i);
continue;
}
}
*/
SType computed;
if (exitSA == Int32.MinValue) {
computed = new SType(-maxDepth, -1);
} else {
computed = new SType(-maxDepth, -maxDepth + exitSA);
}
if (StackEffect.IsKnown) {
if (!computed.IsSubOf(StackEffect)) {
throw new Exception(string.Format(
"word '{0}':"
+ " computed stack effect {1}"
+ " does not match declared {2}",
Name, computed.ToString(),
StackEffect.ToString()));
}
} else {
StackEffect = computed;
}
flowAnalysis = 1;
}
internal override int MaxDataStack {
get {
AnalyseFlow();
return maxDataStack;
}
}
internal override int MaxReturnStack {
get {
AnalyseFlow();
return maxReturnStack;
}
}
}

59
T0/WordNative.cs Normal file
View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
/*
* Class for native words.
*/
class WordNative : Word {
/*
* A type for the native implementation: a method that takes a
* CPU as parameter, and returns nothing.
*/
internal delegate void NativeRun(CPU cpu);
NativeRun code;
internal WordNative(T0Comp owner, string name, NativeRun code)
: base(owner, name)
{
this.code = code;
}
internal WordNative(T0Comp owner, string name,
SType stackEffect, NativeRun code)
: this(owner, name, code)
{
StackEffect = stackEffect;
}
internal override void Run(CPU cpu)
{
code(cpu);
}
}

309
T0/kern.t0 Normal file
View 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));
}