From 4101ee8c8e00be59fb721d2bd116164b02e262be Mon Sep 17 00:00:00 2001 From: PopSlime Date: Sat, 29 Oct 2022 16:22:35 +0800 Subject: [PATCH] Implement collapse instruction. Update docs. --- .../Cryville/Common/Pdt/PdtEvaluatorBase.cs | 37 +++++++--- Assets/Cryville/Common/Pdt/PdtExpression.cs | 71 +++++++++++++++---- Assets/Cryville/Common/Pdt/PdtInternalType.cs | 2 +- 3 files changed, 84 insertions(+), 26 deletions(-) diff --git a/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs b/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs index 9d5fabe..d73caf7 100644 --- a/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs +++ b/Assets/Cryville/Common/Pdt/PdtEvaluatorBase.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using static Cryville.Crtr.Cocos2dFrames; namespace Cryville.Common.Pdt { /// @@ -15,6 +17,7 @@ namespace Cryville.Common.Pdt { readonly StackFrame[] _stack = new StackFrame[256]; readonly byte[] _mem = new byte[0x100000]; bool _revokepttconst; + LinkedListNode _rip; /// /// Evaluates an expression and passes the result to a target operator. /// @@ -24,8 +27,8 @@ namespace Cryville.Common.Pdt { _framecount = 0; _goffset = 0; _revokepttconst = false; - for (var ins = exp.Instructions.First; ins != null; ins = ins.Next) - ins.Value.Execute(this); + for (_rip = exp.Instructions.First; _rip != null; _rip = _rip.Next) + _rip.Value.Execute(this); Operate(target, _framecount, true); if (exp.IsPotentialConstant) { exp.IsConstant = exp.IsPotentialConstant = !_revokepttconst; @@ -39,8 +42,8 @@ namespace Cryville.Common.Pdt { _framecount = 0; _goffset = 0; var il = exp.Instructions; - for (var ins = il.First; ins != null; ins = ins.Next) { - var i = ins.Value; + for (_rip = il.First; _rip != null; _rip = _rip.Next) { + var i = _rip.Value; if (i is PdtInstruction.Operate) { int fc0 = _framecount; int fc1 = ((PdtInstruction.Operate)i).ParamCount; @@ -56,18 +59,16 @@ namespace Cryville.Common.Pdt { } else { var frame = _stack[_framecount - 1]; - il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length)); - ins = ins.Next; - for (var j = 0; j <= fc1; j++) il.Remove(ins.Previous); + _rip = il.AddAfter(_rip, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length)); + for (var j = 0; j <= fc1; j++) il.Remove(_rip.Previous); } } else if (i is PdtInstruction.PushVariable) { i.Execute(this); var frame = _stack[_framecount - 1]; if (frame.Type != PdtInternalType.Undefined) { - il.AddAfter(ins, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length)); - ins = ins.Next; - il.Remove(ins.Previous); + _rip = il.AddAfter(_rip, new PdtInstruction.PushConstant(frame.Type, _mem, frame.Offset, frame.Length)); + il.Remove(_rip.Previous); } } else i.Execute(this); @@ -138,6 +139,22 @@ namespace Cryville.Common.Pdt { op.Call(pmem + _goffset, noset); } } + internal unsafe void Collapse(ref string name, LinkedListNode target) { + fixed (byte* pmem = _mem) { + var frame = _stack[--_framecount]; + if (Collapse(name, new PdtVariableMemory(frame.Type, pmem + frame.Offset, frame.Length))) { + _framecount++; + _rip = target; + } + } + } + /// + /// Gets whether to jump to the target of a collapse instruction. + /// + /// The name of the collapse operator. + /// The top frame in the stack as the parameter. + /// Whether to jump to the target of the collapse instruction. + protected abstract bool Collapse(string name, PdtVariableMemory param); internal unsafe PdtVariableMemory StackAlloc(int type, byte* ptr, int len) { fixed (StackFrame* frame = &_stack[_framecount++]) { frame->Type = type; diff --git a/Assets/Cryville/Common/Pdt/PdtExpression.cs b/Assets/Cryville/Common/Pdt/PdtExpression.cs index 769cedc..2da3b79 100644 --- a/Assets/Cryville/Common/Pdt/PdtExpression.cs +++ b/Assets/Cryville/Common/Pdt/PdtExpression.cs @@ -77,15 +77,42 @@ namespace Cryville.Common.Pdt { return string.Format("op {0}({1})", Name, ParamCount); } } + public class Collapse : PdtInstruction { + private string m_name; + public string Name { get { return m_name; } } + public LinkedListNode Target { get; private set; } + public Collapse(string name, LinkedListNode target) { + m_name = name; + Target = target; + } + internal override void Execute(PdtEvaluatorBase etor) { + etor.Collapse(ref m_name, Target); + } + public override string ToString() { + return string.Format("col {0}{{{1}}}", Name, Target.Value); + } + } } public partial class PdtInterpreter { - readonly static Dictionary pri = new Dictionary { - { '*', 5 }, { '/', 5 }, { '%', 5 }, - { '+', 4 }, { '-', 4 }, - { '=', 3 }, { '<', 3 }, { '>', 3 }, + readonly static Dictionary OP_PRIORITY = new Dictionary { + { '*', 6 }, { '/', 6 }, { '%', 6 }, + { '+', 5 }, { '-', 5 }, + { '=', 4 }, { '<', 4 }, { '>', 4 }, + { '!', 3 }, { '&', 2 }, - { '|', 1 }, { '!', 1 }, + { '|', 1 }, { ',', 0 }, + { '$', -1 }, + }; + readonly static Dictionary OP_TYPE = new Dictionary { + { '*', 0 }, { '/', 0 }, { '%', 0 }, + { '+', 0 }, { '-', 0 }, + { '=', 0 }, { '<', 0 }, { '>', 0 }, + { '!', 0 }, + { '&', 1 }, + { '|', 1 }, + { ',', -2 }, + { '$', -1 }, }; readonly static PdtExpression _emptyexp; @@ -118,7 +145,7 @@ namespace Cryville.Common.Pdt { } public readonly static PdtExpToken EmptyOperator = new PdtExpToken { Type = 0x0080, - Value = "", + Value = "$", }; } @@ -131,7 +158,7 @@ namespace Cryville.Common.Pdt { /// /// -2The expression is in a root scope which ends at a semicolon. /// -1The expression is in a bracketed scope which ends at a closing parenthesis. - /// Any non-negative valuesThe expression is in an auxiliary scope which ends before a closing parenthesis or an operator whose priority is lower (less) than the value of this parameter. + /// Any non-negative valuesThe expression is in an auxiliary scope which ends before a closing parenthesis or an operator whose priority is lower (less) than or equal to the value of this parameter. /// /// /// The parameter count in this (sub)expression. @@ -140,25 +167,33 @@ namespace Cryville.Common.Pdt { PdtExpToken InterpretExp(LinkedList ins, int enc, out int pc, PdtExpToken? token = null) { PdtExpToken t1, t2; int insc0 = ins.Count; + Dictionary, string> colp = null; pc = 1; if (token == null) t1 = PdtExpToken.EmptyOperator; - else t1 = token.Value; + else { + t1 = token.Value; + if (OP_TYPE[t1.Value[0]] == 1) + colp = new Dictionary, string> { { ins.Last, token.Value.Value } }; + } while (true) { t2 = InterpretExpBlock(ins); panic: switch (t2.Type) { case 0x0080: - if (t1.Value != "") { - int p1 = pri[t1.Value[0]]; - int p2 = pri[t2.Value[0]]; + if (OP_TYPE[t1.Value[0]] != -1) { + int p1 = OP_PRIORITY[t1.Value[0]]; + int p2 = OP_PRIORITY[t2.Value[0]]; if (p2 <= enc) goto exit; if (p2 > p1) { int _; t2 = InterpretExp(ins, p1, out _, t2); goto panic; } - if (t1.Value != ",") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2)); - else pc++; + switch (OP_TYPE[t1.Value[0]]) { + case 0: ins.AddLast(new PdtInstruction.Operate(t1.Value, 2)); break; + case 1: colp.Add(ins.Last, t2.Value); break; + default: pc++; break; + } } t1 = t2; break; @@ -171,8 +206,14 @@ namespace Cryville.Common.Pdt { } } exit: - if (t1.Value != "," && t1.Value != "") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2)); - else if (t1.Value == ",") pc++; + switch (OP_TYPE[t1.Value[0]]) { + case 0: ins.AddLast(new PdtInstruction.Operate(t1.Value, 2)); break; + case 1: + foreach (var p in colp) + ins.AddAfter(p.Key, new PdtInstruction.Collapse(p.Value, ins.Last)); + break; + case -2: pc++; break; + } return t2; } diff --git a/Assets/Cryville/Common/Pdt/PdtInternalType.cs b/Assets/Cryville/Common/Pdt/PdtInternalType.cs index a1fcc4a..51ede3f 100644 --- a/Assets/Cryville/Common/Pdt/PdtInternalType.cs +++ b/Assets/Cryville/Common/Pdt/PdtInternalType.cs @@ -17,7 +17,7 @@ /// public readonly static int String = "string".GetHashCode(); /// - /// A sequence of UTF-16 code units representing the name of an undefined variable. + /// A sequence of UTF-16 code units, with a prefix indicating the number of the code units, representing the name of an undefined variable. /// public readonly static int Undefined = "undefined".GetHashCode(); ///