Add project files.
This commit is contained in:
247
Assets/Cryville/Common/Pdt/PdtExpression.cs
Normal file
247
Assets/Cryville/Common/Pdt/PdtExpression.cs
Normal file
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Cryville.Common.Pdt {
|
||||
/// <summary>
|
||||
/// PDT expression.
|
||||
/// </summary>
|
||||
public class PdtExpression {
|
||||
internal LinkedList<PdtInstruction> Instructions;
|
||||
/// <summary>
|
||||
/// Whether the value of this expression is constant.
|
||||
/// </summary>
|
||||
/// <remarks>The value of this property is <c>false</c> until it is optimized.</remarks>
|
||||
public bool IsConstant { get; internal set; }
|
||||
internal bool IsPotentialConstant;
|
||||
internal PdtExpression(LinkedList<PdtInstruction> ins) {
|
||||
Instructions = ins;
|
||||
}
|
||||
public override string ToString() {
|
||||
string r = "";
|
||||
bool flag = false;
|
||||
foreach (PdtInstruction ins in Instructions) {
|
||||
if (flag) r += "; ";
|
||||
r += ins.ToString();
|
||||
flag = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
internal abstract class PdtInstruction {
|
||||
internal abstract void Execute(PdtEvaluatorBase etor);
|
||||
public class PushConstant : PdtInstruction {
|
||||
public int Type { get; private set; }
|
||||
public byte[] Value { get; private set; }
|
||||
public PushConstant(int type, byte[] value) {
|
||||
Type = type;
|
||||
Value = value;
|
||||
}
|
||||
public PushConstant(int type, byte[] buffer, int offset, int len) {
|
||||
Type = type;
|
||||
Value = new byte[len];
|
||||
Array.Copy(buffer, offset, Value, 0, len);
|
||||
}
|
||||
internal override void Execute(PdtEvaluatorBase etor) {
|
||||
etor.PushConstant(Type, Value);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("pushc ({0:x8}){1}", Type, BitConverter.ToString(Value));
|
||||
}
|
||||
}
|
||||
public class PushVariable : PdtInstruction {
|
||||
private string m_name;
|
||||
public string Name { get { return m_name; } }
|
||||
public PushVariable(string name) {
|
||||
m_name = name;
|
||||
}
|
||||
internal override void Execute(PdtEvaluatorBase etor) {
|
||||
etor.PushVariable(ref m_name);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("pushv {0}", Name);
|
||||
}
|
||||
}
|
||||
public class Operate : PdtInstruction {
|
||||
private string m_name;
|
||||
public string Name { get { return m_name; } }
|
||||
public int ParamCount { get; private set; }
|
||||
public Operate(string name, int paramCount) {
|
||||
m_name = name;
|
||||
ParamCount = paramCount;
|
||||
}
|
||||
internal override void Execute(PdtEvaluatorBase etor) {
|
||||
etor.Operate(ref m_name, ParamCount);
|
||||
}
|
||||
public override string ToString() {
|
||||
return string.Format("op {0}({1})", Name, ParamCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
public partial class PdtInterpreter<T> {
|
||||
readonly static Dictionary<char, int> pri = new Dictionary<char, int> {
|
||||
{ '*', 5 }, { '/', 5 }, { '%', 5 },
|
||||
{ '+', 4 }, { '-', 4 },
|
||||
{ '=', 3 }, { '<', 3 }, { '>', 3 },
|
||||
{ '&', 2 },
|
||||
{ '|', 1 }, { '!', 1 },
|
||||
{ ',', 0 },
|
||||
};
|
||||
|
||||
readonly static PdtExpression _emptyexp;
|
||||
static PdtInterpreter() {
|
||||
var ins = new LinkedList<PdtInstruction>();
|
||||
ins.AddLast(new PdtInstruction.PushConstant(
|
||||
PdtInternalType.Number, BitConverter.GetBytes(1f)
|
||||
));
|
||||
_emptyexp = new PdtExpression(ins);
|
||||
}
|
||||
|
||||
PdtExpToken GetToken() {
|
||||
ws();
|
||||
var result = new PdtExpToken {
|
||||
Type = ct & 0x0fe0
|
||||
};
|
||||
switch (result.Type) {
|
||||
case 0x0020: result.Value = GetIdentifier(); break;
|
||||
case 0x0040: result.Value = GetNumber(); break;
|
||||
case 0x0100: result.Value = GetString(); break;
|
||||
default: result.Value = cc.ToString(); Position++; break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private struct PdtExpToken {
|
||||
public int Type { get; set; }
|
||||
public string Value { get; set; }
|
||||
public override string ToString() {
|
||||
return string.Format("0x{0:x4}: {1}", Type, Value);
|
||||
}
|
||||
public readonly static PdtExpToken EmptyOperator = new PdtExpToken {
|
||||
Type = 0x0080,
|
||||
Value = "",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets an expression from the current position and loads it onto an instruction set.
|
||||
/// </summary>
|
||||
/// <param name="ins">The instruction set.</param>
|
||||
/// <param name="enc">
|
||||
/// <para>The enclosing scope type of the (sub)expression. May be one of the following:</para>
|
||||
/// <list type="bullet">
|
||||
/// <item><term><c>-2</c></term><description>The expression is in a root scope which ends at a semicolon.</description></item>
|
||||
/// <item><term><c>-1</c></term><description>The expression is in a bracketed scope which ends at a closing parenthesis.</description></item>
|
||||
/// <item><term>Any non-negative values</term><description>The 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.</description></item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
/// <param name="pc">The parameter count in this (sub)expression.</param>
|
||||
/// <param name="token">The token already parsed but required for the interpretation of the subexpression.</param>
|
||||
/// <returns>The expression token following this (sub)expression.</returns>
|
||||
PdtExpToken InterpretExp(LinkedList<PdtInstruction> ins, int enc, out int pc, PdtExpToken? token = null) {
|
||||
PdtExpToken t1, t2;
|
||||
int insc0 = ins.Count;
|
||||
pc = 1;
|
||||
if (token == null) t1 = PdtExpToken.EmptyOperator;
|
||||
else t1 = token.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 (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++;
|
||||
}
|
||||
t1 = t2;
|
||||
break;
|
||||
case 0x0400:
|
||||
if (enc == -2) throw new FormatException("Expression not enclosed correctly: Too many closing brackets");
|
||||
if (ins.Count == insc0) pc = 0;
|
||||
goto exit;
|
||||
case 0x0800:
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
if (t1.Value != "," && t1.Value != "") ins.AddLast(new PdtInstruction.Operate(t1.Value, 2));
|
||||
else if (t1.Value == ",") pc++;
|
||||
return t2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interprets an expression block which consists of several adjacent constants and subexpressions, optionally with a unary operator.
|
||||
/// </summary>
|
||||
/// <param name="ins">The instruction set.</param>
|
||||
/// <returns>The expression token following this expression block.</returns>
|
||||
PdtExpToken InterpretExpBlock(LinkedList<PdtInstruction> ins) {
|
||||
var t = GetToken();
|
||||
if (t.Type == 0x0080) {
|
||||
var r = InterpretExpBlock(ins);
|
||||
ins.AddLast(new PdtInstruction.Operate(t.Value, 1));
|
||||
return r;
|
||||
}
|
||||
bool flag = false;
|
||||
PdtExpToken? buf = null;
|
||||
while (true) {
|
||||
if (buf != null && t.Type != 0x0200) {
|
||||
PdtExpression def;
|
||||
if (defs.TryGetValue(buf.Value.Value, out def)) {
|
||||
foreach (var i in def.Instructions) ins.AddLast(i);
|
||||
}
|
||||
else ins.AddLast(new PdtInstruction.PushVariable(buf.Value.Value));
|
||||
buf = null;
|
||||
TryPushAdjMul(ins, ref flag);
|
||||
}
|
||||
switch (t.Type) {
|
||||
case 0x0020:
|
||||
buf = t;
|
||||
break;
|
||||
case 0x0040:
|
||||
float num = float.Parse(t.Value);
|
||||
ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.Number, BitConverter.GetBytes(num)));
|
||||
break;
|
||||
case 0x0100:
|
||||
int strlen = t.Value.Length;
|
||||
unsafe {
|
||||
var strbuf = new byte[strlen * sizeof(char) + sizeof(int)];
|
||||
fixed (byte* psuffix = strbuf) {
|
||||
*(int*)psuffix = strlen;
|
||||
}
|
||||
Encoding.Unicode.GetBytes(t.Value, 0, strlen, strbuf, sizeof(int));
|
||||
ins.AddLast(new PdtInstruction.PushConstant(PdtInternalType.String, strbuf));
|
||||
}
|
||||
break;
|
||||
case 0x0200:
|
||||
int pc;
|
||||
InterpretExp(ins, -1, out pc);
|
||||
if (buf != null) {
|
||||
ins.AddLast(new PdtInstruction.Operate(buf.Value.Value, pc));
|
||||
buf = null;
|
||||
}
|
||||
else if (pc > 1) {
|
||||
ins.AddLast(new PdtInstruction.Operate(",", pc));
|
||||
}
|
||||
else if (pc == 0)
|
||||
throw new FormatException("Empty subexpression");
|
||||
break;
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
if (buf == null) TryPushAdjMul(ins, ref flag);
|
||||
t = GetToken();
|
||||
}
|
||||
}
|
||||
void TryPushAdjMul(LinkedList<PdtInstruction> ins, ref bool flag) {
|
||||
if (flag) ins.AddLast(new PdtInstruction.Operate("*", 2));
|
||||
else flag = true;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user