From f356be4769bc55be78f00763e92e2b3259e1f11d Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 19:44:21 +0400 Subject: [PATCH 01/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20VM.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf-cs.sln | 26 ++++++++ dwarf-cs/dwarf.core/BytecodeBuilder.cs | 40 ++++++++++++ .../dwarf.core/Properties/AssemblyInfo.cs | 36 ++++++++++ dwarf-cs/dwarf.core/Vm.cs | 54 +++++++++++++++ dwarf-cs/dwarf.core/dwarf.core.csproj | 55 ++++++++++++++++ dwarf-cs/tests/Properties/AssemblyInfo.cs | 36 ++++++++++ dwarf-cs/tests/VmTests.cs | 30 +++++++++ dwarf-cs/tests/packages.config | 4 ++ dwarf-cs/tests/tests.csproj | 65 +++++++++++++++++++ 9 files changed, 346 insertions(+) create mode 100644 dwarf-cs/dwarf-cs.sln create mode 100644 dwarf-cs/dwarf.core/BytecodeBuilder.cs create mode 100644 dwarf-cs/dwarf.core/Properties/AssemblyInfo.cs create mode 100644 dwarf-cs/dwarf.core/Vm.cs create mode 100644 dwarf-cs/dwarf.core/dwarf.core.csproj create mode 100644 dwarf-cs/tests/Properties/AssemblyInfo.cs create mode 100644 dwarf-cs/tests/VmTests.cs create mode 100644 dwarf-cs/tests/packages.config create mode 100644 dwarf-cs/tests/tests.csproj diff --git a/dwarf-cs/dwarf-cs.sln b/dwarf-cs/dwarf-cs.sln new file mode 100644 index 0000000..58c730c --- /dev/null +++ b/dwarf-cs/dwarf-cs.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dwarf.core", "dwarf.core\dwarf.core.csproj", "{FD95899A-79B4-4424-A531-92F0935AC39C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{E48C4A1A-A404-466F-9F66-5D9A9C80896B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FD95899A-79B4-4424-A531-92F0935AC39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD95899A-79B4-4424-A531-92F0935AC39C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD95899A-79B4-4424-A531-92F0935AC39C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD95899A-79B4-4424-A531-92F0935AC39C}.Release|Any CPU.Build.0 = Release|Any CPU + {E48C4A1A-A404-466F-9F66-5D9A9C80896B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E48C4A1A-A404-466F-9F66-5D9A9C80896B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E48C4A1A-A404-466F-9F66-5D9A9C80896B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E48C4A1A-A404-466F-9F66-5D9A9C80896B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs new file mode 100644 index 0000000..043d3e0 --- /dev/null +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; + +namespace dwarf.core +{ + public class BytecodeBuilder + { + private List bytecode = new List(); + + public List Bytecode + { + get { return bytecode; } + } + + public BytecodeBuilder halt() + { + bytecode.Add(0x00); + return this; + } + + public BytecodeBuilder iadd() + { + bytecode.Add(0x01); + return this; + } + + public BytecodeBuilder ipushc(long c) + { + bytecode.Add(0x06); + bytecode.AddRange(BitConverter.GetBytes(c)); + return this; + } + + public BytecodeBuilder print() + { + bytecode.Add(0x0E); + return this; + } + } +} diff --git a/dwarf-cs/dwarf.core/Properties/AssemblyInfo.cs b/dwarf-cs/dwarf.core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..07695e0 --- /dev/null +++ b/dwarf-cs/dwarf.core/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("dwarf.core")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("dwarf.core")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("71dc51e8-79d2-4c7f-8de8-c2ff5c0fb6fd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs new file mode 100644 index 0000000..783fbf9 --- /dev/null +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace dwarf.core +{ + public class Vm + { + private byte[] bytecode; + private readonly StringWriter printer; + + private Stack stack = new Stack(); + private bool halted; + private int pc; + + public Vm(IEnumerable bytecode, StringWriter printer) + { + this.bytecode = bytecode.ToArray(); + this.printer = printer; + } + + public void Run() + { + pc = 0; + halted = false; + + while (!halted) + { + var instruction = bytecode[pc++]; + + switch (instruction) + { + case 0x00: + halted = true; + break; + + case 0x01: + stack.Push(stack.Pop() + stack.Pop()); + break; + + case 0x06: + stack.Push(BitConverter.ToInt64(bytecode, pc)); + pc += sizeof(long); + break; + + case 0x0E: + printer.WriteLine(stack.Pop()); + break; + } + } + } + } +} diff --git a/dwarf-cs/dwarf.core/dwarf.core.csproj b/dwarf-cs/dwarf.core/dwarf.core.csproj new file mode 100644 index 0000000..a4fa346 --- /dev/null +++ b/dwarf-cs/dwarf.core/dwarf.core.csproj @@ -0,0 +1,55 @@ + + + + + Debug + AnyCPU + {FD95899A-79B4-4424-A531-92F0935AC39C} + Library + Properties + dwarf.core + dwarf.core + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dwarf-cs/tests/Properties/AssemblyInfo.cs b/dwarf-cs/tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ca6dc4b --- /dev/null +++ b/dwarf-cs/tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("tests")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("281b1730-55eb-4d41-ba05-00b4cd105478")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs new file mode 100644 index 0000000..fe70d07 --- /dev/null +++ b/dwarf-cs/tests/VmTests.cs @@ -0,0 +1,30 @@ +using System.IO; +using dwarf.core; +using NUnit.Framework; + +namespace tests +{ + [TestFixture] + public class VmTests + { + [Test] + public void BasicTest() + { + var builder = new BytecodeBuilder(); + + builder + .ipushc(1) + .ipushc(2) + .iadd() + .print() + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual("3\r\n", printer.ToString()); + } + } +} diff --git a/dwarf-cs/tests/packages.config b/dwarf-cs/tests/packages.config new file mode 100644 index 0000000..5a3253f --- /dev/null +++ b/dwarf-cs/tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dwarf-cs/tests/tests.csproj b/dwarf-cs/tests/tests.csproj new file mode 100644 index 0000000..e5be6b9 --- /dev/null +++ b/dwarf-cs/tests/tests.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {E48C4A1A-A404-466F-9F66-5D9A9C80896B} + Library + Properties + tests + tests + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + + + + + + + + + + + + + + + + + + {FD95899A-79B4-4424-A531-92F0935AC39C} + dwarf.core + + + + + \ No newline at end of file From 40f84f6dd2c888a1ff002d8928c65e207592f288 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 19:48:54 +0400 Subject: [PATCH 02/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D1=83?= =?UTF-8?q?=20isub=20=D0=B8=20dup.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 12 ++++++++++++ dwarf-cs/dwarf.core/Vm.cs | 8 ++++++++ dwarf-cs/tests/VmTests.cs | 22 +++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index 043d3e0..0b81231 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -24,6 +24,18 @@ public BytecodeBuilder iadd() return this; } + public BytecodeBuilder isub() + { + bytecode.Add(0x02); + return this; + } + + public BytecodeBuilder dup() + { + bytecode.Add(0x05); + return this; + } + public BytecodeBuilder ipushc(long c) { bytecode.Add(0x06); diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs index 783fbf9..c8917ab 100644 --- a/dwarf-cs/dwarf.core/Vm.cs +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -39,6 +39,14 @@ public void Run() stack.Push(stack.Pop() + stack.Pop()); break; + case 0x02: + stack.Push(stack.Pop() - stack.Pop()); + break; + + case 0x05: + stack.Push(stack.Peek()); + break; + case 0x06: stack.Push(BitConverter.ToInt64(bytecode, pc)); pc += sizeof(long); diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index fe70d07..fda3eb1 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -8,7 +8,7 @@ namespace tests public class VmTests { [Test] - public void BasicTest() + public void Test1() { var builder = new BytecodeBuilder(); @@ -26,5 +26,25 @@ public void BasicTest() Assert.AreEqual("3\r\n", printer.ToString()); } + + [Test] + public void Test2() + { + var builder = new BytecodeBuilder(); + + builder + .ipushc(1) + .dup() + .isub() + .print() + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual("0\r\n", printer.ToString()); + } } } From c64ba3bce2272792329a2d7b6a7d8aa7c1081296 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 19:58:08 +0400 Subject: [PATCH 03/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20imul.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 6 ++++++ dwarf-cs/dwarf.core/Vm.cs | 4 ++++ dwarf-cs/tests/VmTests.cs | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index 0b81231..8ee2b73 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -30,6 +30,12 @@ public BytecodeBuilder isub() return this; } + public BytecodeBuilder imul() + { + bytecode.Add(0x03); + return this; + } + public BytecodeBuilder dup() { bytecode.Add(0x05); diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs index c8917ab..c77825c 100644 --- a/dwarf-cs/dwarf.core/Vm.cs +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -43,6 +43,10 @@ public void Run() stack.Push(stack.Pop() - stack.Pop()); break; + case 0x03: + stack.Push(stack.Pop() * stack.Pop()); + break; + case 0x05: stack.Push(stack.Peek()); break; diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index fda3eb1..7f50ee0 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -46,5 +46,25 @@ public void Test2() Assert.AreEqual("0\r\n", printer.ToString()); } + + [Test] + public void Test3() + { + var builder = new BytecodeBuilder(); + + builder + .ipushc(3) + .ipushc(5) + .imul() + .print() + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual("15\r\n", printer.ToString()); + } } } From 8b75e83c3c5c763500fc5fc4e280a9bce583d52d Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 20:43:07 +0400 Subject: [PATCH 04/19] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=B1=D0=B0=D0=B7=D0=BE=D0=B2=D1=83?= =?UTF-8?q?=D1=8E=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D1=83?= =?UTF-8?q?=20jz.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 49 ++++++++++++++++++++++++++ dwarf-cs/dwarf.core/Label.cs | 6 ++++ dwarf-cs/dwarf.core/Vm.cs | 8 +++++ dwarf-cs/dwarf.core/dwarf.core.csproj | 1 + dwarf-cs/tests/VmTests.cs | 25 +++++++++++++ 5 files changed, 89 insertions(+) create mode 100644 dwarf-cs/dwarf.core/Label.cs diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index 8ee2b73..9a965da 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -7,6 +7,35 @@ public class BytecodeBuilder { private List bytecode = new List(); + private Dictionary labels = new Dictionary(); + private Dictionary> fixups = new Dictionary>(); + + private int LabelOffset(Label label) + { + if (labels.ContainsKey(label)) + return labels[label] - bytecode.Count + 4; + + if (!fixups.ContainsKey(label)) + fixups.Add(label, new List()); + + fixups[label].Add(bytecode.Count); + return bytecode.Count + 4; + } + + private void DoFixups(List offsets, int address) + { + foreach (var offset in offsets) + { + var pc = BitConverter.ToInt32(bytecode.GetRange(offset, 4).ToArray(), 0); + var b = BitConverter.GetBytes(address - pc); + + for (int i = 0; i < 4; i++) + { + bytecode[offset + i] = b[i]; + } + } + } + public List Bytecode { get { return bytecode; } @@ -49,10 +78,30 @@ public BytecodeBuilder ipushc(long c) return this; } + public BytecodeBuilder jz(Label label) + { + bytecode.Add(0x0A); + bytecode.AddRange(BitConverter.GetBytes(LabelOffset(label))); + return this; + } + public BytecodeBuilder print() { bytecode.Add(0x0E); return this; } + + public BytecodeBuilder label(Label label) + { + if (fixups.ContainsKey(label)) + { + DoFixups(fixups[label], bytecode.Count); + fixups.Remove(label); + } + + labels.Add(label, bytecode.Count); + + return this; + } } } diff --git a/dwarf-cs/dwarf.core/Label.cs b/dwarf-cs/dwarf.core/Label.cs new file mode 100644 index 0000000..6c4aac0 --- /dev/null +++ b/dwarf-cs/dwarf.core/Label.cs @@ -0,0 +1,6 @@ +namespace dwarf.core +{ + public class Label + { + } +} diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs index c77825c..0c7a78d 100644 --- a/dwarf-cs/dwarf.core/Vm.cs +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -56,6 +56,14 @@ public void Run() pc += sizeof(long); break; + case 0x0A: + var off = BitConverter.ToInt32(bytecode, pc); + pc += sizeof (int); + + if (stack.Pop() == 0) + pc = pc + off; + break; + case 0x0E: printer.WriteLine(stack.Pop()); break; diff --git a/dwarf-cs/dwarf.core/dwarf.core.csproj b/dwarf-cs/dwarf.core/dwarf.core.csproj index a4fa346..b16a7dc 100644 --- a/dwarf-cs/dwarf.core/dwarf.core.csproj +++ b/dwarf-cs/dwarf.core/dwarf.core.csproj @@ -40,6 +40,7 @@ + diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index 7f50ee0..185df35 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -66,5 +66,30 @@ public void Test3() Assert.AreEqual("15\r\n", printer.ToString()); } + + [Test] + public void Test4() + { + var builder = new BytecodeBuilder(); + + var l1 = new Label(); + + builder + .ipushc(1) + .jz(l1) + .ipushc(10) + .print() + .label(l1) + .ipushc(20) + .print() + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual("10\r\n20\r\n", printer.ToString()); + } } } From a1354e48e8cd71dcf834ea2534efbd31ea884e36 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 20:52:32 +0400 Subject: [PATCH 05/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=20=D0=BD=D0=B0=20JMP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/tests/VmTests.cs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index 185df35..c87b870 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -91,5 +91,36 @@ public void Test4() Assert.AreEqual("10\r\n20\r\n", printer.ToString()); } + + [Test] + public void Test5() + { + var builder = new BytecodeBuilder(); + + var l1 = new Label(); + var l2 = new Label(); + var l3 = new Label(); + + builder + .jmp(l2) + + .label(l1) + .ipushc(10) + .print() + .jmp(l3) + + .label(l2) + .jmp(l1) + + .label(l3) + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual("10\r\n", printer.ToString()); + } } } From 05c07311779bf0bc81de5bb96e32abe2c627d460 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 20:56:02 +0400 Subject: [PATCH 06/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA=D1=83?= =?UTF-8?q?=20JMP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Кроме того, исправил баг с вычислением адреса перехода. --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 9 ++++++++- dwarf-cs/dwarf.core/Vm.cs | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index 9a965da..4ddf553 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -13,7 +13,7 @@ public class BytecodeBuilder private int LabelOffset(Label label) { if (labels.ContainsKey(label)) - return labels[label] - bytecode.Count + 4; + return labels[label] - (bytecode.Count + 4); if (!fixups.ContainsKey(label)) fixups.Add(label, new List()); @@ -78,6 +78,13 @@ public BytecodeBuilder ipushc(long c) return this; } + public BytecodeBuilder jmp(Label label) + { + bytecode.Add(0x09); + bytecode.AddRange(BitConverter.GetBytes(LabelOffset(label))); + return this; + } + public BytecodeBuilder jz(Label label) { bytecode.Add(0x0A); diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs index 0c7a78d..b577e52 100644 --- a/dwarf-cs/dwarf.core/Vm.cs +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -56,13 +56,24 @@ public void Run() pc += sizeof(long); break; + case 0x09: + { + var off = BitConverter.ToInt32(bytecode, pc); + pc += sizeof (int); + + pc = pc + off; + break; + } + case 0x0A: + { var off = BitConverter.ToInt32(bytecode, pc); pc += sizeof (int); if (stack.Pop() == 0) pc = pc + off; break; + } case 0x0E: printer.WriteLine(stack.Pop()); From e84a84df3e134850911d942a102adf2542d3eac5 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 20:56:31 +0400 Subject: [PATCH 07/19] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/tests/VmTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index c87b870..dec4069 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -79,7 +79,8 @@ public void Test4() .jz(l1) .ipushc(10) .print() - .label(l1) + + .label(l1) .ipushc(20) .print() .halt(); From 9e94af90d91925e2eaec05f82e3930eb4b079823 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 21:01:45 +0400 Subject: [PATCH 08/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20helper.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/tests/VmTests.cs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index dec4069..663e219 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Text; using dwarf.core; using NUnit.Framework; @@ -7,6 +8,18 @@ namespace tests [TestFixture] public class VmTests { + private static string Multiline(params string[] lines) + { + var builder = new StringBuilder(); + + foreach (var line in lines) + { + builder.AppendLine(line); + } + + return builder.ToString(); + } + [Test] public void Test1() { @@ -24,7 +37,7 @@ public void Test1() vm.Run(); - Assert.AreEqual("3\r\n", printer.ToString()); + Assert.AreEqual(Multiline("3"), printer.ToString()); } [Test] @@ -44,7 +57,7 @@ public void Test2() vm.Run(); - Assert.AreEqual("0\r\n", printer.ToString()); + Assert.AreEqual(Multiline("0"), printer.ToString()); } [Test] @@ -64,7 +77,7 @@ public void Test3() vm.Run(); - Assert.AreEqual("15\r\n", printer.ToString()); + Assert.AreEqual(Multiline("15"), printer.ToString()); } [Test] @@ -90,7 +103,7 @@ public void Test4() vm.Run(); - Assert.AreEqual("10\r\n20\r\n", printer.ToString()); + Assert.AreEqual(Multiline("10", "20"), printer.ToString()); } [Test] @@ -121,7 +134,7 @@ public void Test5() vm.Run(); - Assert.AreEqual("10\r\n", printer.ToString()); + Assert.AreEqual(Multiline("10"), printer.ToString()); } } } From 8059ea5491d39b4e6b0eca89dd95770107bfdb6e Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 21:08:48 +0400 Subject: [PATCH 09/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20eq.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 6 ++++++ dwarf-cs/dwarf.core/Vm.cs | 10 ++++++++++ dwarf-cs/tests/VmTests.cs | 26 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index 4ddf553..1b64e28 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -92,6 +92,12 @@ public BytecodeBuilder jz(Label label) return this; } + public BytecodeBuilder eq() + { + bytecode.Add(0x0D); + return this; + } + public BytecodeBuilder print() { bytecode.Add(0x0E); diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs index b577e52..f0d1fd0 100644 --- a/dwarf-cs/dwarf.core/Vm.cs +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -75,6 +75,16 @@ public void Run() break; } + case 0x0D: + { + var a = stack.Pop(); + var b = stack.Pop(); + + stack.Push(a == b ? 1 : 0); + + break; + } + case 0x0E: printer.WriteLine(stack.Pop()); break; diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index 663e219..bbcf073 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -136,5 +136,31 @@ public void Test5() Assert.AreEqual(Multiline("10"), printer.ToString()); } + + [Test] + public void Test6() + { + var builder = new BytecodeBuilder(); + + builder + .ipushc(10) + .ipushc(10) + .eq() + .print() + + .ipushc(10) + .ipushc(11) + .eq() + .print() + + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual(Multiline("1", "0"), printer.ToString()); + } } } From 64d0acbaab332af53e471f9c2044598076d9920d Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 12 Aug 2014 21:23:02 +0400 Subject: [PATCH 10/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20jnz.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 7 +++++++ dwarf-cs/dwarf.core/Vm.cs | 17 ++++++++++++++- dwarf-cs/tests/VmTests.cs | 29 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index 1b64e28..f5d45a7 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -92,6 +92,13 @@ public BytecodeBuilder jz(Label label) return this; } + public BytecodeBuilder jnz(Label label) + { + bytecode.Add(0x0B); + bytecode.AddRange(BitConverter.GetBytes(LabelOffset(label))); + return this; + } + public BytecodeBuilder eq() { bytecode.Add(0x0D); diff --git a/dwarf-cs/dwarf.core/Vm.cs b/dwarf-cs/dwarf.core/Vm.cs index f0d1fd0..feb760d 100644 --- a/dwarf-cs/dwarf.core/Vm.cs +++ b/dwarf-cs/dwarf.core/Vm.cs @@ -40,8 +40,13 @@ public void Run() break; case 0x02: - stack.Push(stack.Pop() - stack.Pop()); + { + var b = stack.Pop(); + var a = stack.Pop(); + + stack.Push(a - b); break; + } case 0x03: stack.Push(stack.Pop() * stack.Pop()); @@ -75,6 +80,16 @@ public void Run() break; } + case 0x0B: + { + var off = BitConverter.ToInt32(bytecode, pc); + pc += sizeof(int); + + if (stack.Pop() != 0) + pc = pc + off; + break; + } + case 0x0D: { var a = stack.Pop(); diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index bbcf073..d5a10ea 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -162,5 +162,34 @@ public void Test6() Assert.AreEqual(Multiline("1", "0"), printer.ToString()); } + + [Test] + public void Test7() + { + var builder = new BytecodeBuilder(); + + var loop = new Label(); + + builder + .ipushc(10) + + .label(loop) + .dup() + .print() + + .ipushc(1) + .isub() + .dup() + .jnz(loop) + + .halt(); + + var printer = new StringWriter(); + var vm = new Vm(builder.Bytecode, printer); + + vm.Run(); + + Assert.AreEqual(Multiline("10", "9", "8", "7", "6", "5", "4", "3", "2", "1"), printer.ToString()); + } } } From 890069183f0e2d827ea842229b052355c48e8d6f Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Wed, 13 Aug 2014 16:09:04 +0400 Subject: [PATCH 11/19] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=B2=20BytecodeBuilder=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=20=D0=BD=D1=83=D0=B6=D0=BD=D1=8B=D0=B5=20=D0=B8?= =?UTF-8?q?=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B8?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/BytecodeBuilder.cs | 26 ++++ dwarf-cs/tests/BytecodeBuilderTests.cs | 186 +++++++++++++++++++++++++ dwarf-cs/tests/tests.csproj | 1 + 3 files changed, 213 insertions(+) create mode 100644 dwarf-cs/tests/BytecodeBuilderTests.cs diff --git a/dwarf-cs/dwarf.core/BytecodeBuilder.cs b/dwarf-cs/dwarf.core/BytecodeBuilder.cs index f5d45a7..48d819e 100644 --- a/dwarf-cs/dwarf.core/BytecodeBuilder.cs +++ b/dwarf-cs/dwarf.core/BytecodeBuilder.cs @@ -65,6 +65,12 @@ public BytecodeBuilder imul() return this; } + public BytecodeBuilder idiv() + { + bytecode.Add(0x04); + return this; + } + public BytecodeBuilder dup() { bytecode.Add(0x05); @@ -78,6 +84,20 @@ public BytecodeBuilder ipushc(long c) return this; } + public BytecodeBuilder ipushreg(short reg) + { + bytecode.Add(0x07); + bytecode.AddRange(BitConverter.GetBytes(reg)); + return this; + } + + public BytecodeBuilder ipopreg(short reg) + { + bytecode.Add(0x08); + bytecode.AddRange(BitConverter.GetBytes(reg)); + return this; + } + public BytecodeBuilder jmp(Label label) { bytecode.Add(0x09); @@ -99,6 +119,12 @@ public BytecodeBuilder jnz(Label label) return this; } + public BytecodeBuilder icmp() + { + bytecode.Add(0x0C); + return this; + } + public BytecodeBuilder eq() { bytecode.Add(0x0D); diff --git a/dwarf-cs/tests/BytecodeBuilderTests.cs b/dwarf-cs/tests/BytecodeBuilderTests.cs new file mode 100644 index 0000000..854768b --- /dev/null +++ b/dwarf-cs/tests/BytecodeBuilderTests.cs @@ -0,0 +1,186 @@ +using dwarf.core; +using NUnit.Framework; + +namespace tests +{ + [TestFixture] + public class BytecodeBuilderTests + { + [Test] + public void HaltTest() + { + var builder = new BytecodeBuilder(); + + builder + .halt(); + + var expexted = new byte[] + { + 0x00 // HALT + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void OperationsTest() + { + var builder = new BytecodeBuilder(); + + builder + .iadd() + .isub() + .imul() + .idiv(); + + var expexted = new byte[] + { + 0x01, // IADD + 0x02, // ISUB + 0x03, // IMUL + 0x04 // IDIV + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void ConstTest() + { + var builder = new BytecodeBuilder(); + + builder + .ipushc(0x0102030405060708); + + var expexted = new byte[] + { + 0x06, + 0x08, 0x07, 0x06, 0x05, + 0x04, 0x03, 0x02, 0x01 // IPUSHC 0x0102030405060708 + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void JmpTest() + { + var builder = new BytecodeBuilder(); + + var loop = new Label(); + var next = new Label(); + + builder + .label(loop) + .jmp(loop) + .jmp(next) + .label(next); + + var expexted = new byte[] + { + 0x09, 0xFB, 0xFF, 0xFF, 0xFF, // JMP -5 + 0x09, 0x00, 0x00, 0x00, 0x00 // JMP 0 + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void JzTest() + { + var builder = new BytecodeBuilder(); + + var loop = new Label(); + var next = new Label(); + + builder + .label(loop) + .jz(loop) + .jz(next) + .label(next); + + var expexted = new byte[] + { + 0x0A, 0xFB, 0xFF, 0xFF, 0xFF, // JZ -5 + 0x0A, 0x00, 0x00, 0x00, 0x00 // JZ 0 + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void JnzTest() + { + var builder = new BytecodeBuilder(); + + var loop = new Label(); + var next = new Label(); + + builder + .label(loop) + .jnz(loop) + .jnz(next) + .label(next); + + var expexted = new byte[] + { + 0x0B, 0xFB, 0xFF, 0xFF, 0xFF, // JNZ -5 + 0x0B, 0x00, 0x00, 0x00, 0x00 // JNZ 0 + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void PushPopRegTest() + { + var builder = new BytecodeBuilder(); + + builder + .ipushreg(0x01) + .ipopreg(0x02); + + var expexted = new byte[] + { + 0x07, 0x01, 0x00, // IPUSHREG 1 + 0x08, 0x02, 0x00 // IPOPREG 2 + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void IcmpEqTest() + { + var builder = new BytecodeBuilder(); + + builder + .icmp() + .eq(); + + var expexted = new byte[] + { + 0x0C, // ICMP + 0x0D // EQ + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + + [Test] + public void PrintTest() + { + var builder = new BytecodeBuilder(); + + builder + .print(); + + var expexted = new byte[] + { + 0x0E // PRINT + }; + + Assert.AreEqual(expexted, builder.Bytecode); + } + } +} diff --git a/dwarf-cs/tests/tests.csproj b/dwarf-cs/tests/tests.csproj index e5be6b9..ddc6d64 100644 --- a/dwarf-cs/tests/tests.csproj +++ b/dwarf-cs/tests/tests.csproj @@ -42,6 +42,7 @@ + From dcc96f1f4a2f7e2d667c457310e6cc4f0c6cf121 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Wed, 13 Aug 2014 16:27:05 +0400 Subject: [PATCH 12/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20Lexer=20=D0=B8=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D0=B9=20=D1=82=D0=B5=D1=81=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/dwarf.core.csproj | 2 ++ dwarf-cs/dwarf.core/lang/Lexer.cs | 12 +++++++++++ dwarf-cs/dwarf.core/lang/Tokens.cs | 7 +++++++ dwarf-cs/tests/LexerTests.cs | 30 +++++++++++++++++++++++++++ dwarf-cs/tests/TestBase.cs | 19 +++++++++++++++++ dwarf-cs/tests/VmTests.cs | 15 +------------- dwarf-cs/tests/tests.csproj | 2 ++ 7 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 dwarf-cs/dwarf.core/lang/Lexer.cs create mode 100644 dwarf-cs/dwarf.core/lang/Tokens.cs create mode 100644 dwarf-cs/tests/LexerTests.cs create mode 100644 dwarf-cs/tests/TestBase.cs diff --git a/dwarf-cs/dwarf.core/dwarf.core.csproj b/dwarf-cs/dwarf.core/dwarf.core.csproj index b16a7dc..3e327cd 100644 --- a/dwarf-cs/dwarf.core/dwarf.core.csproj +++ b/dwarf-cs/dwarf.core/dwarf.core.csproj @@ -41,6 +41,8 @@ + + diff --git a/dwarf-cs/dwarf.core/lang/Lexer.cs b/dwarf-cs/dwarf.core/lang/Lexer.cs new file mode 100644 index 0000000..727bb14 --- /dev/null +++ b/dwarf-cs/dwarf.core/lang/Lexer.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace dwarf.core.lang +{ + public class Lexer + { + public IEnumerable Tokenize(string source) + { + yield break; + } + } +} diff --git a/dwarf-cs/dwarf.core/lang/Tokens.cs b/dwarf-cs/dwarf.core/lang/Tokens.cs new file mode 100644 index 0000000..c614306 --- /dev/null +++ b/dwarf-cs/dwarf.core/lang/Tokens.cs @@ -0,0 +1,7 @@ +namespace dwarf.core.lang +{ + public class Token + { + + } +} diff --git a/dwarf-cs/tests/LexerTests.cs b/dwarf-cs/tests/LexerTests.cs new file mode 100644 index 0000000..e32ba13 --- /dev/null +++ b/dwarf-cs/tests/LexerTests.cs @@ -0,0 +1,30 @@ +using System; +using dwarf.core.lang; +using NUnit.Framework; + +namespace tests +{ + [TestFixture] + public class LexerTests : TestBase + { + [Test] + public void ExpressionsTest() + { + var source = Multiline( + "a + b", + "a - b", + "a / b", + "a * b"); + + var lexer = new Lexer(); + var actual = String.Join("", lexer.Tokenize(source)); + + const string expected = "[a] + [b] " + + "[a] - [b] " + + "[a] / [b] " + + "[a] * [b] "; + + Assert.AreEqual(expected, actual); + } + } +} diff --git a/dwarf-cs/tests/TestBase.cs b/dwarf-cs/tests/TestBase.cs new file mode 100644 index 0000000..2165edb --- /dev/null +++ b/dwarf-cs/tests/TestBase.cs @@ -0,0 +1,19 @@ +using System.Text; + +namespace tests +{ + public class TestBase + { + protected static string Multiline(params string[] lines) + { + var builder = new StringBuilder(); + + foreach (var line in lines) + { + builder.AppendLine(line); + } + + return builder.ToString(); + } + } +} diff --git a/dwarf-cs/tests/VmTests.cs b/dwarf-cs/tests/VmTests.cs index d5a10ea..d12168a 100644 --- a/dwarf-cs/tests/VmTests.cs +++ b/dwarf-cs/tests/VmTests.cs @@ -1,25 +1,12 @@ using System.IO; -using System.Text; using dwarf.core; using NUnit.Framework; namespace tests { [TestFixture] - public class VmTests + public class VmTests:TestBase { - private static string Multiline(params string[] lines) - { - var builder = new StringBuilder(); - - foreach (var line in lines) - { - builder.AppendLine(line); - } - - return builder.ToString(); - } - [Test] public void Test1() { diff --git a/dwarf-cs/tests/tests.csproj b/dwarf-cs/tests/tests.csproj index ddc6d64..cc49c30 100644 --- a/dwarf-cs/tests/tests.csproj +++ b/dwarf-cs/tests/tests.csproj @@ -43,6 +43,8 @@ + + From 6ccd950a4b230fbb5bd2fa17e8efbb4c251fa45b Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Mon, 18 Aug 2014 16:22:59 +0400 Subject: [PATCH 13/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20IfThenElseTest.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/tests/LexerTests.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/dwarf-cs/tests/LexerTests.cs b/dwarf-cs/tests/LexerTests.cs index e32ba13..317be65 100644 --- a/dwarf-cs/tests/LexerTests.cs +++ b/dwarf-cs/tests/LexerTests.cs @@ -26,5 +26,26 @@ public void ExpressionsTest() Assert.AreEqual(expected, actual); } + + [Test] + public void IfThenElseTest() + { + var source = Multiline( + "if (a == b) then {", + " a := a - b;", + "} else {", + " a := 0;", + "}"); + + var lexer = new Lexer(); + var actual = String.Join("", lexer.Tokenize(source)); + + const string expected = "if ([a] == [b]) then { " + + "[a] := [a] - [b]; " + + "[a] / [b] " + + "[a] * [b] "; + + Assert.AreEqual(expected, actual); + } } } From 2bb9a1cde458cf4ad86aa9614ad57bca247e0ffe Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Mon, 18 Aug 2014 16:30:56 +0400 Subject: [PATCH 14/19] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=82=D0=B5=D1=81=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/tests/LexerTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwarf-cs/tests/LexerTests.cs b/dwarf-cs/tests/LexerTests.cs index 317be65..f6f4db2 100644 --- a/dwarf-cs/tests/LexerTests.cs +++ b/dwarf-cs/tests/LexerTests.cs @@ -42,8 +42,9 @@ public void IfThenElseTest() const string expected = "if ([a] == [b]) then { " + "[a] := [a] - [b]; " + - "[a] / [b] " + - "[a] * [b] "; + "} else { " + + "[a] := <0>; " + + "}"; Assert.AreEqual(expected, actual); } From 536c5cb4a853dd4d25af2c564dfaed88356d26d3 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 2 Sep 2014 20:28:24 +0400 Subject: [PATCH 15/19] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D1=82=D0=B5=D1=81=D1=82.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/tests/LexerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwarf-cs/tests/LexerTests.cs b/dwarf-cs/tests/LexerTests.cs index f6f4db2..ad32038 100644 --- a/dwarf-cs/tests/LexerTests.cs +++ b/dwarf-cs/tests/LexerTests.cs @@ -44,7 +44,7 @@ public void IfThenElseTest() "[a] := [a] - [b]; " + "} else { " + "[a] := <0>; " + - "}"; + "} "; Assert.AreEqual(expected, actual); } From 0256199f04d6f42621e3b8876d6d6e8044e499a3 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Tue, 2 Sep 2014 20:32:17 +0400 Subject: [PATCH 16/19] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BB=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B9=20lexer.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/lang/Lexer.cs | 190 ++++++++++++++++++++++++++++- dwarf-cs/dwarf.core/lang/Tokens.cs | 54 +++++++- 2 files changed, 241 insertions(+), 3 deletions(-) diff --git a/dwarf-cs/dwarf.core/lang/Lexer.cs b/dwarf-cs/dwarf.core/lang/Lexer.cs index 727bb14..004bc92 100644 --- a/dwarf-cs/dwarf.core/lang/Lexer.cs +++ b/dwarf-cs/dwarf.core/lang/Lexer.cs @@ -1,12 +1,198 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; namespace dwarf.core.lang { + interface ITokenRule + { + bool Check(char c, int pos); + Token CreateToken(string src); + } + + internal class IdentifierRule : ITokenRule + { + public bool Check(char c, int pos) + { + return pos == 0 ? Char.IsLetter(c) : Char.IsLetterOrDigit(c); + } + + public Token CreateToken(string src) + { + return new IdentifierToken(src); + } + } + + internal class KeywordRule : ITokenRule + { + private string keyword; + + public KeywordRule(string keyword) + { + this.keyword = keyword; + } + + public bool Check(char c, int pos) + { + return pos < keyword.Length && keyword[pos] == c; + } + + public Token CreateToken(string src) + { + return new KeywordToken(src); + } + } + + internal class NumberRule : ITokenRule + { + public bool Check(char c, int pos) + { + if (pos == 0 && (c == '-' && c == '+')) + return true; + else + return Char.IsNumber(c); + } + + public Token CreateToken(string src) + { + return new ConstantToken(long.Parse(src)); + } + } + + internal class WhitespaceRule : ITokenRule + { + public bool Check(char c, int pos) + { + return Char.IsWhiteSpace(c); + } + + public Token CreateToken(string src) + { + return new WhitespaceToken(); + } + } + + internal class Matcher + { + private ITokenRule rule; + private bool stop; + private string matched; + + public Token Token { get; private set; } + + public Matcher(ITokenRule rule) + { + this.rule = rule; + } + + public void Reset() + { + stop = false; + matched = String.Empty; + Token = null; + } + + public void Update(char c) + { + if (stop) + return; + + if (rule.Check(c, matched.Length)) + { + matched += c; + } + else + { + stop = true; + } + + if (stop && matched.Length > 0) + { + Token = rule.CreateToken(matched); + } + } + } + public class Lexer { + private static readonly ITokenRule[] Rules = + { + new WhitespaceRule(), + + new KeywordRule("if"), + new KeywordRule("then"), + new KeywordRule("else"), + + new KeywordRule("+"), + new KeywordRule("-"), + new KeywordRule("*"), + new KeywordRule("/"), + + new KeywordRule("while"), + + new KeywordRule("{"), + new KeywordRule("}"), + + new KeywordRule("("), + new KeywordRule(")"), + + new KeywordRule("=="), + + new KeywordRule(";"), + + new KeywordRule(":="), + + new IdentifierRule(), + new NumberRule(), + }; + public IEnumerable Tokenize(string source) { - yield break; + var matchers = Rules.Select(rule => new Matcher(rule)).ToArray(); + + var state = 0; + var pos = 0; + + // HACK + source += (char) 0xffff; + + while (pos < source.Length) + { + if (state == 0) + { + foreach (var matcher in matchers) + { + matcher.Reset(); + } + + state = 1; + } + + foreach (var matcher in matchers) + { + matcher.Update(source[pos]); + } + + Token token = null; + foreach (var matcher in matchers) + { + if (matcher.Token != null) + { + token = matcher.Token; + break; + } + } + + if (token != null) + { + state = 0; + yield return token; + } + else + { + pos ++; + } + } } } } diff --git a/dwarf-cs/dwarf.core/lang/Tokens.cs b/dwarf-cs/dwarf.core/lang/Tokens.cs index c614306..882794d 100644 --- a/dwarf-cs/dwarf.core/lang/Tokens.cs +++ b/dwarf-cs/dwarf.core/lang/Tokens.cs @@ -2,6 +2,58 @@ { public class Token { - + } + + public class KeywordToken : Token + { + private string keyword; + + public KeywordToken(string keyword) + { + this.keyword = keyword; + } + + public override string ToString() + { + return keyword; + } + } + + public class IdentifierToken : Token + { + private string name; + + public IdentifierToken(string name) + { + this.name = name; + } + + public override string ToString() + { + return string.Format("[{0}]", name); + } + } + + public class ConstantToken : Token + { + private long value; + + public ConstantToken(long value) + { + this.value = value; + } + + public override string ToString() + { + return string.Format("<{0}>", value); + } + } + + public class WhitespaceToken : Token + { + public override string ToString() + { + return " "; + } } } From 3bb794f74fe910d48427952b01f8a475c087d876 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Wed, 3 Sep 2014 16:59:51 +0400 Subject: [PATCH 17/19] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B1=D0=B0=D0=B3=20=D1=81=20=D0=BF=D0=B0=D1=80?= =?UTF-8?q?=D1=81=D0=B8=D0=BD=D0=B3=D0=BE=D0=BC=20signed=20numbers.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/lang/Lexer.cs | 59 ++++++++++++++++++++++++------- dwarf-cs/tests/LexerTests.cs | 19 ++++++++++ 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/dwarf-cs/dwarf.core/lang/Lexer.cs b/dwarf-cs/dwarf.core/lang/Lexer.cs index 004bc92..de5d1d4 100644 --- a/dwarf-cs/dwarf.core/lang/Lexer.cs +++ b/dwarf-cs/dwarf.core/lang/Lexer.cs @@ -47,15 +47,42 @@ internal class NumberRule : ITokenRule { public bool Check(char c, int pos) { - if (pos == 0 && (c == '-' && c == '+')) - return true; + return Char.IsNumber(c); + } + + public Token CreateToken(string src) + { + return new ConstantToken(long.Parse(src)); + } + } + + internal class SignedNumberRule : ITokenRule + { + public bool Check(char c, int pos) + { + if (pos == 0) + return c == '-' || c == '+'; else return Char.IsNumber(c); } public Token CreateToken(string src) { - return new ConstantToken(long.Parse(src)); + long c; + + // FIXME: Это по сути затычка для ситуации, когда src не является + // правильной константой, но check возвращает true потому, + // что проверяет только один символ. По сути это ошибка + // дизайна. + + if (Int64.TryParse(src, out c)) + { + return new ConstantToken(c); + } + else + { + return null; + } } } @@ -75,10 +102,10 @@ public Token CreateToken(string src) internal class Matcher { private ITokenRule rule; - private bool stop; private string matched; public Token Token { get; private set; } + public bool Stop { get; private set; } public Matcher(ITokenRule rule) { @@ -87,14 +114,14 @@ public Matcher(ITokenRule rule) public void Reset() { - stop = false; + Stop = false; matched = String.Empty; Token = null; } public void Update(char c) { - if (stop) + if (Stop) return; if (rule.Check(c, matched.Length)) @@ -103,10 +130,10 @@ public void Update(char c) } else { - stop = true; + Stop = true; } - if (stop && matched.Length > 0) + if (Stop && matched.Length > 0) { Token = rule.CreateToken(matched); } @@ -119,6 +146,9 @@ public class Lexer { new WhitespaceRule(), + new NumberRule(), + new SignedNumberRule(), + new KeywordRule("if"), new KeywordRule("then"), new KeywordRule("else"), @@ -143,7 +173,6 @@ public class Lexer new KeywordRule(":="), new IdentifierRule(), - new NumberRule(), }; public IEnumerable Tokenize(string source) @@ -174,12 +203,16 @@ public IEnumerable Tokenize(string source) } Token token = null; - foreach (var matcher in matchers) + + if (matchers.All(m => m.Stop)) { - if (matcher.Token != null) + foreach (var matcher in matchers) { - token = matcher.Token; - break; + if (matcher.Token != null) + { + token = matcher.Token; + break; + } } } diff --git a/dwarf-cs/tests/LexerTests.cs b/dwarf-cs/tests/LexerTests.cs index ad32038..e89afe0 100644 --- a/dwarf-cs/tests/LexerTests.cs +++ b/dwarf-cs/tests/LexerTests.cs @@ -48,5 +48,24 @@ public void IfThenElseTest() Assert.AreEqual(expected, actual); } + + [Test] + public void ConstTest() + { + var source = Multiline( + "a := 10", + "a := -12", + "a := +13" + ); + + var lexer = new Lexer(); + var actual = String.Join("", lexer.Tokenize(source)); + + const string expected = "[a] := <10> " + + "[a] := <-12> " + + "[a] := <13> "; + + Assert.AreEqual(expected, actual); + } } } From 5b4ab7bb7010b099a127c57a9756f1c7d9f0ef54 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Wed, 3 Sep 2014 17:37:47 +0400 Subject: [PATCH 18/19] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B4=D0=B8=D0=B0=D0=B3=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20Exception.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/lang/Lexer.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dwarf-cs/dwarf.core/lang/Lexer.cs b/dwarf-cs/dwarf.core/lang/Lexer.cs index de5d1d4..21b96ed 100644 --- a/dwarf-cs/dwarf.core/lang/Lexer.cs +++ b/dwarf-cs/dwarf.core/lang/Lexer.cs @@ -181,6 +181,7 @@ public IEnumerable Tokenize(string source) var state = 0; var pos = 0; + var tok = ""; // HACK source += (char) 0xffff; @@ -194,6 +195,7 @@ public IEnumerable Tokenize(string source) matcher.Reset(); } + tok = ""; state = 1; } @@ -214,6 +216,12 @@ public IEnumerable Tokenize(string source) break; } } + + if (token == null && source[pos] != 0xffff) + { + tok += source[pos]; + throw new Exception(String.Format("Unknown token: {0}", tok)); + } } if (token != null) @@ -223,6 +231,7 @@ public IEnumerable Tokenize(string source) } else { + tok += source[pos]; pos ++; } } From a8241b0350ada499ea938527bd716823c2ed6bb8 Mon Sep 17 00:00:00 2001 From: sergey-raevskiy Date: Mon, 22 Sep 2014 17:56:44 +0400 Subject: [PATCH 19/19] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B1=D0=B0=D0=B3.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dwarf-cs/dwarf.core/lang/Lexer.cs | 11 +++++++++-- dwarf-cs/tests/LexerTests.cs | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/dwarf-cs/dwarf.core/lang/Lexer.cs b/dwarf-cs/dwarf.core/lang/Lexer.cs index 21b96ed..1fbfd74 100644 --- a/dwarf-cs/dwarf.core/lang/Lexer.cs +++ b/dwarf-cs/dwarf.core/lang/Lexer.cs @@ -107,6 +107,11 @@ internal class Matcher public Token Token { get; private set; } public bool Stop { get; private set; } + public int MatchedLen + { + get { return matched.Length; } + } + public Matcher(ITokenRule rule) { this.rule = rule; @@ -208,12 +213,14 @@ public IEnumerable Tokenize(string source) if (matchers.All(m => m.Stop)) { + int len = 0; + foreach (var matcher in matchers) { - if (matcher.Token != null) + if (matcher.Token != null && matcher.MatchedLen > len) { token = matcher.Token; - break; + len = matcher.MatchedLen; } } diff --git a/dwarf-cs/tests/LexerTests.cs b/dwarf-cs/tests/LexerTests.cs index e89afe0..0f92235 100644 --- a/dwarf-cs/tests/LexerTests.cs +++ b/dwarf-cs/tests/LexerTests.cs @@ -49,6 +49,20 @@ public void IfThenElseTest() Assert.AreEqual(expected, actual); } + [Test] + public void AmbiguousIdentifiersTest() + { + var source = Multiline( + "if iff"); + + var lexer = new Lexer(); + var actual = String.Join("", lexer.Tokenize(source)); + + const string expected = "if [iff] "; + + Assert.AreEqual(expected, actual); + } + [Test] public void ConstTest() {