├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── Program.cs └── script │ ├── brance-loop.txt │ ├── function.txt │ ├── print.txt │ ├── table.txt │ └── typeof.txt └── src ├── Lib └── Lightbrary.cs ├── Parse ├── Keywords.cs ├── Parser.cs ├── Scanner.cs └── Tokens.cs ├── RunTime ├── Instructor.cs ├── RefPartBase.cs ├── RunEnvironment.cs └── ScriptObject.cs └── Util ├── ExpInfo.cs ├── ExpMark.cs └── ScriptUtility.cs /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScriptInterpreter 2 | Implementation of the MyScript scripting language engine. 3 | 4 | ## Introduction 5 | * Recursive syntax analysis of the decline 6 | * Base on .Net 4.0 dynamic language runtime 7 | * Similar Lua/Javascript grammar 8 | * Support dynamic language common functions, such as table (association array), 9 | * function as the first type, closure, uncertain parameters,Meta table (similar to the Lua Metatable) 10 | * C# friendly interoperability 11 | 12 | ## Sample 13 | ```script 14 | local i = "hello wrod" 15 | print(i) 16 | 17 | for(i = 0; i < 10; i++) { 18 | print(i) 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /examples/Program.cs: -------------------------------------------------------------------------------- 1 | using ScriptInterpreter.RunTime; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Examples 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | RunEnvironment.Instance.Init(); 16 | if (args.Length > 0) 17 | { 18 | string scriptFileName = args[0]; 19 | using (StreamReader objReader = new StreamReader(scriptFileName)) 20 | { 21 | StringBuilder sb = new StringBuilder(); 22 | 23 | string s = objReader.ReadLine(); 24 | while (s != null) 25 | { 26 | sb.Append(s); 27 | s = objReader.ReadLine(); 28 | } 29 | 30 | RunEnvironment.Instance.Interprete(sb.ToString()); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/script/brance-loop.txt: -------------------------------------------------------------------------------- 1 | local i = "hello" 2 | 3 | if(i == "hello") { 4 | print("is hello") 5 | } 6 | else if(i == "word") 7 | { 8 | print("is word") 9 | } 10 | else 11 | { 12 | print("not hello,not word") 13 | } 14 | 15 | i = 23 > 10 ? "correct" : "wrong" 16 | 17 | print(i) 18 | 19 | 20 | for(i = 0; i < 10 ; i++) 21 | { 22 | print(i .. " ") 23 | } 24 | 25 | 26 | i = 0; 27 | while( i < 100) 28 | { 29 | print(i .. " ") 30 | if(i == 10) 31 | { 32 | break; 33 | } 34 | ++i 35 | } 36 | 37 | 38 | i = 0 39 | do 40 | { 41 | print(i .. " "); 42 | ++i 43 | }while( i < 10) 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/script/function.txt: -------------------------------------------------------------------------------- 1 | function a() 2 | { 3 | return 1234; 4 | } 5 | 6 | b = function(i,j,k) 7 | { 8 | return i + j + k 9 | } 10 | 11 | c = function(...) 12 | { 13 | print(args[0]); 14 | print(args[1]); 15 | print(args[2]); 16 | print(args[3]); 17 | } 18 | 19 | 20 | /* closure example */ 21 | d = function(i) 22 | { 23 | local k = 10 24 | return function(j) { 25 | return i + j + k 26 | } 27 | } 28 | 29 | 30 | e = function(i) 31 | { 32 | return i + b(i,i,i); 33 | } 34 | 35 | print(a()); 36 | print("\n") 37 | 38 | print(b(1,2,3)) 39 | print("\n") 40 | 41 | print(b(1,2,3,6,7,8)) 42 | print("\n") 43 | 44 | c(2345,"yanghuan",8900) 45 | 46 | f = d(34); 47 | print(f(21)) 48 | 49 | print(e(10)) 50 | print("\n") 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/script/print.txt: -------------------------------------------------------------------------------- 1 | print("hello,word!") 2 | print("\n") 3 | 4 | print("1234") 5 | print("\n") 6 | 7 | 8 | print("hello," .. "word!") 9 | print("\n") 10 | 11 | print(11 + 8 * 12) 12 | print("\n") 13 | 14 | print(false) 15 | print("\n") 16 | 17 | print("1234") 18 | print("\n") 19 | 20 | print("yang","huan",5667,2323,false) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/script/table.txt: -------------------------------------------------------------------------------- 1 | i = { email : "sy.yanghuan@gmail.com" , name : "yanghuan" } 2 | 3 | 4 | print(i.email); 5 | print("\n") 6 | 7 | 8 | print(i.name) 9 | print("\n") 10 | 11 | 12 | i.f = function() { 13 | return 123456; 14 | } 15 | 16 | print(i.f()); 17 | print("\n") 18 | 19 | 20 | i.array = { 1,2,3} 21 | print(i.array[0],i.array[1],i.array[2]) 22 | -------------------------------------------------------------------------------- /examples/script/typeof.txt: -------------------------------------------------------------------------------- 1 | local i = typeof(print) 2 | print(i) 3 | print("\n") 4 | 5 | i = typeof("yanghuan") 6 | print(i) 7 | print("\n") 8 | 9 | i = typeof(1234) 10 | print(i) 11 | print("\n") 12 | 13 | i = typeof({ 1,2,3,4,6,7 }) 14 | print(i) 15 | print("\n") 16 | 17 | i = typeof({ email : "sy.yanghuan@gmail.com" , name : "yanghuan" }) 18 | print(i) 19 | print("\n") 20 | 21 | i = function() { 22 | return 123 23 | } 24 | 25 | print(i) 26 | print("\n") -------------------------------------------------------------------------------- /src/Lib/Lightbrary.cs: -------------------------------------------------------------------------------- 1 | using ScriptInterpreter.RunTime; 2 | using System.Diagnostics; 3 | 4 | 5 | 6 | 7 | namespace ScriptInterpreter.Lib 8 | { 9 | using SW = System.Windows; 10 | using System.Linq.Expressions; 11 | using System; 12 | using ScriptInterpreter.Util; 13 | 14 | public static class Lightbrary 15 | { 16 | public static void OutPut() 17 | { 18 | StackState s = RunEnvironment.Instance.LocalStack; 19 | //获得第一个参数 20 | ScriptObject arg1 = s.GetStackVar(0); 21 | 22 | TablePart tablePart = arg1.Value.RefPartHandle.ConverToTablePart(); 23 | 24 | for (int i = 0; i < tablePart.Count; i++) 25 | { 26 | Console.Write(tablePart.ArrayPart[i].GetString() + " "); 27 | } 28 | 29 | s.SetReturnVoid(); 30 | } 31 | 32 | public static void GetTypeOf() 33 | { 34 | StackState s = RunEnvironment.Instance.LocalStack; 35 | 36 | ScriptObject arg1 = s.GetStackVar(0); 37 | 38 | ScriptObject resoult = ScriptObject.CreateString(arg1.GetTypeof()); 39 | 40 | s.SetReturn(resoult); 41 | } 42 | 43 | public static void LoadString() 44 | { 45 | StackState s = RunEnvironment.Instance.LocalStack; 46 | 47 | ScriptObject arg1 = s.GetStackVar(0); 48 | 49 | if (arg1.Type == ScriptInterpreter.RunTime.ValueType.STRING) 50 | { 51 | Expression e = RunEnvironment.Instance.CompilationUnit(arg1.Value.RefPartHandle.StringValue); 52 | 53 | Func a = Expression.Lambda>(e).Compile(); 54 | 55 | ScriptObject resoult = a(); 56 | 57 | if (resoult == null) s.SetReturnVoid(); 58 | 59 | else s.SetReturn(resoult); 60 | 61 | return; 62 | } 63 | s.SetReturnVoid(); 64 | } 65 | 66 | public static void Error() 67 | { 68 | StackState s = RunEnvironment.Instance.LocalStack; 69 | 70 | ScriptObject arg1 = s.GetStackVar(0); 71 | 72 | if (arg1.Type == ScriptInterpreter.RunTime.ValueType.STRING) 73 | { 74 | string message = arg1.GetString(); 75 | 76 | throw new ScriptRunTimeException(message); 77 | } 78 | s.SetReturnVoid(); 79 | } 80 | 81 | 82 | public static void SetMetatable() 83 | { 84 | StackState s = RunEnvironment.Instance.LocalStack; 85 | 86 | ScriptObject arg1 = s.GetStackVar(0); 87 | 88 | ScriptObject arg2 = s.GetStackVar(1); 89 | 90 | if (arg1.Type != ScriptInterpreter.RunTime.ValueType.TABLE || arg2.Type != ScriptInterpreter.RunTime.ValueType.TABLE) return; 91 | 92 | TablePart table = arg1.Value.RefPartHandle.ConverToTablePart(); 93 | 94 | table.MetaTable = arg2; 95 | } 96 | 97 | public static void GetMetatable() 98 | { 99 | StackState s = RunEnvironment.Instance.LocalStack; 100 | 101 | ScriptObject arg1 = s.GetStackVar(0); 102 | 103 | if (arg1.Type == ScriptInterpreter.RunTime.ValueType.TABLE) 104 | { 105 | ScriptObject metaTable = arg1.Value.RefPartHandle.ConverToTablePart().MetaTable; 106 | 107 | if (metaTable!=null) 108 | { 109 | s.SetReturn(metaTable); 110 | } 111 | } 112 | s.SetReturnVoid(); 113 | } 114 | 115 | public static void LoadLIB() 116 | { 117 | RunEnvironment r = RunEnvironment.Instance; 118 | 119 | bool res = r.LoadFunction("print", OutPut,0,true); 120 | 121 | res = r.LoadFunction("typeof", GetTypeOf, 1); 122 | 123 | res = r.LoadFunction("loadstring", LoadString, 1); 124 | 125 | res = r.LoadFunction("error", Error, 1); 126 | 127 | res = r.LoadFunction("setmetatable", SetMetatable, 2); 128 | 129 | res = r.LoadFunction("getmetatable", GetMetatable, 1); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Parse/Keywords.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ScriptInterpreter.Util; 3 | 4 | namespace ScriptInterpreter.Parse 5 | { 6 | public class Keywords : Tokens 7 | { 8 | private Dictionary _table = new Dictionary(); 9 | 10 | public Keywords() 11 | { 12 | enterKeyword("+", PLUS); 13 | enterKeyword("-", SUB); 14 | enterKeyword("!", BANG); 15 | enterKeyword("%", PERCENT); 16 | enterKeyword("*", STAR); 17 | enterKeyword("/", SLASH); 18 | enterKeyword(">", GT); 19 | enterKeyword("<", LT); 20 | enterKeyword("?", QUES); 21 | enterKeyword(":", COLON); 22 | enterKeyword("=", EQ); 23 | enterKeyword("++", PLUSPLUS); 24 | enterKeyword("--", SUBSUB); 25 | enterKeyword("==", EQEQ); 26 | enterKeyword("<=", LTEQ); 27 | enterKeyword(">=", GTEQ); 28 | enterKeyword("!=", BANGEQ); 29 | 30 | enterKeyword("local",LOCAL); 31 | enterKeyword("function", FUNCTION); 32 | enterKeyword("nil", Nil); 33 | enterKeyword("this",THIS); 34 | enterKeyword("false", FALSE); 35 | enterKeyword("true", TRUE); 36 | enterKeyword("do", DO); 37 | enterKeyword("else", ELSE); 38 | enterKeyword("for", FOR); 39 | enterKeyword("if", IF); 40 | enterKeyword("return", RETURN); 41 | enterKeyword("while", WHILE); 42 | enterKeyword("break", BREAK); 43 | } 44 | 45 | private void enterKeyword(string s, int token) 46 | { 47 | _table.Add(s,token); 48 | } 49 | 50 | internal int key(string name) 51 | { 52 | int com; 53 | if (_table.TryGetValue(name, out com) == true) 54 | { 55 | return com; 56 | } 57 | return IDENTIFIER; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Parse/Parser.cs: -------------------------------------------------------------------------------- 1 | using ScriptInterpreter.Util; 2 | using System; 3 | using System.Linq.Expressions; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Diagnostics.Contracts; 7 | using ScriptInterpreter.RunTime; 8 | 9 | namespace ScriptInterpreter.Parse 10 | { 11 | public sealed class Parser : Tokens 12 | { 13 | private Scanner _scanner; 14 | 15 | public Scanner S 16 | { 17 | get { return _scanner; } 18 | } 19 | 20 | 21 | /** 22 | * When terms are parsed, the mode determines which is expected: 23 | * mode = EXPR : an expression 24 | * mode = TYPE : a type 25 | * mode = NOPARAMS : no parameters allowed for type 26 | */ 27 | private const int EXPR = 1; 28 | private const int TYPE = 2; 29 | private const int NOPARAMS = 4; 30 | 31 | private const int LValue = 8; 32 | 33 | /** 34 | * The current mode. 35 | */ 36 | private int mode = 0; 37 | private int lastmode = 0; 38 | 39 | 40 | //语法树构造 41 | private ExpMark _expMark = new ExpMark(); 42 | 43 | public ExpMark E 44 | { 45 | get { return _expMark; } 46 | } 47 | 48 | public Parser(Scanner scanner) 49 | { 50 | _scanner = scanner; 51 | } 52 | 53 | internal Expression CompilationUnit() 54 | { 55 | Instructor.CompileIndexStack.LogIndex(); 56 | 57 | funcReturnStack.Push(Expression.Label()); 58 | 59 | BlockExpression body = BlockStatements(); 60 | 61 | Instructor.CompileIndexStack.PopIndex(); 62 | 63 | Expression t = E.At(S.Pos).CompilationUnit(new TupleStruct(0, false), functionList, body, funcReturnStack.Pop()); 64 | 65 | functionList.Clear(); 66 | 67 | return t; 68 | } 69 | 70 | private string Ident() 71 | { 72 | if (S.Token == IDENTIFIER) 73 | { 74 | string name = S.TokenString; 75 | S.NextToken(); 76 | return name; 77 | } 78 | else 79 | { 80 | throw ScriptCompileException.CreateIsNotIdentifier(S.TokenString); 81 | } 82 | } 83 | 84 | private Expression VariableInitializer() 85 | { 86 | return S.Token == LBRACE ? TableInitializer(null) : GetExpression(); 87 | } 88 | 89 | 90 | private KeyValuePair GetTableField() 91 | { 92 | string key = null; 93 | 94 | if (S.IsTableValueKey() == true) 95 | { 96 | if (S.Token == IDENTIFIER) 97 | { 98 | key = Ident(); 99 | } 100 | else 101 | { 102 | key = S.TokenString; 103 | S.NextToken(); 104 | } 105 | Accept(COLON); 106 | } 107 | return new KeyValuePair(key, VariableInitializer()); 108 | } 109 | 110 | 111 | private Expression TableInitializer(Expression t) 112 | { 113 | Accept(LBRACE); // { 114 | 115 | List> elems = new List>(); 116 | 117 | if (S.Token != RBRACE) 118 | { 119 | elems.Add(GetTableField()); 120 | 121 | while (S.Token == COMMA) 122 | { 123 | S.NextToken(); 124 | elems.Add(GetTableField()); 125 | } 126 | } 127 | 128 | Accept(RBRACE); // } 129 | 130 | return E.At(S.Pos).Table(t, elems); 131 | } 132 | 133 | public void Accept(int token) 134 | { 135 | if (token == SEMI) // ; 处理,可以不加; 136 | { 137 | if (S.Token == token) S.NextToken(); 138 | return; 139 | } 140 | if (S.Token == token) 141 | { 142 | S.NextToken(); 143 | } 144 | else 145 | { 146 | throw ScriptCompileException.CreateSyntaxError(S.Line,S.Col,S.Token,S.TokenString); 147 | } 148 | } 149 | private List functionList = new List(); 150 | 151 | //用于return 语句返回 152 | private Stack funcReturnStack = new Stack(); 153 | 154 | 155 | private Stack>> _upValueStack = new Stack>>(); 156 | 157 | public Stack>> UpValueStack 158 | { 159 | get { return _upValueStack; } 160 | } 161 | 162 | private Expression MethodDeclaratorRest() 163 | { 164 | List> upvalues = new List>(); 165 | 166 | UpValueStack.Push(upvalues); 167 | 168 | Instructor.CompileIndexStack.LogIndex(); 169 | 170 | var info = FormalParameters(); 171 | 172 | funcReturnStack.Push(Expression.Label()); 173 | 174 | Accept(LBRACE); // { 175 | 176 | BlockExpression body = BlockStatements(); //方法体 177 | 178 | Accept(RBRACE); // } 179 | 180 | Instructor.CompileIndexStack.PopIndex(); 181 | 182 | return E.At(S.Pos).MethodDef(info, body, funcReturnStack.Pop(), UpValueStack.Pop()); 183 | } 184 | 185 | //获得Block 186 | private BlockExpression Block() 187 | { 188 | 189 | Accept(LBRACE); // { 190 | 191 | Instructor.CompileIndexStack.EnterBlock(); 192 | 193 | BlockExpression t = BlockStatements(); 194 | 195 | int count = Instructor.CompileIndexStack.OutBlock(); 196 | 197 | Accept(RBRACE); // } 198 | 199 | return E.At(S.Pos).Block(t,count); 200 | } 201 | //c 202 | private BlockExpression BlockStatements() 203 | { 204 | List stats = new List(); 205 | while (true) 206 | { 207 | switch (S.Token) // } 208 | { 209 | case RBRACE: // } 210 | 211 | case EOF: 212 | return Expression.Block(stats); 213 | 214 | case LBRACE: // { 215 | case IF: // if 216 | 217 | case FOR: // for 218 | 219 | case WHILE: // while 220 | 221 | case DO: // do 222 | 223 | case RETURN: //return 224 | 225 | case BREAK: //break; 226 | 227 | case CONTINUE: 228 | 229 | stats.Add(Statement()); 230 | break; 231 | 232 | case LOCAL: 233 | S.NextToken(); 234 | 235 | if (S.Token == IDENTIFIER) 236 | { 237 | stats.Add(VariableDeclaratorsRest(Ident())); 238 | } 239 | else if (S.Token == FUNCTION) 240 | { 241 | S.NextToken(); 242 | stats.Add(E.At(S.Pos).LocalVarDef(Ident(), MethodDeclaratorRest())); 243 | } 244 | else 245 | { 246 | throw ScriptCompileException.CreateSyntaxError(S.Line,S.Col,S.Token,S.TokenString); 247 | } 248 | Accept(SEMI); 249 | break; 250 | 251 | case FUNCTION: 252 | S.NextToken(); 253 | 254 | functionList.Add(E.At(S.Pos).MethodDef(Ident(), MethodDeclaratorRest())); 255 | 256 | break; 257 | 258 | default: 259 | Expression t = Term(EXPR | TYPE); 260 | 261 | Contract.Assert(t != null); 262 | 263 | stats.Add(t); 264 | 265 | Accept(SEMI); 266 | break; 267 | } 268 | } 269 | } 270 | 271 | private Expression VariableDeclaratorsRest(string localName) 272 | { 273 | List vdefs = new List(); 274 | 275 | vdefs.Add(VariableDeclaratorRest(localName)); 276 | 277 | while (S.Token == COMMA) 278 | { 279 | S.NextToken(); 280 | vdefs.Add(VariableDeclaratorRest(Ident())); 281 | } 282 | return Expression.Block(vdefs); 283 | } 284 | 285 | private Expression VariableDeclaratorRest(string localName) 286 | { 287 | Expression init; 288 | 289 | if (S.Token == EQ) // = 复制 290 | { 291 | S.NextToken(); 292 | 293 | init = VariableInitializer(); 294 | } 295 | else 296 | { 297 | init = Instructor.GetNil().GetConstantExpression(); 298 | } 299 | return E.At(S.Pos).LocalVarDef(localName, init); 300 | } 301 | // 用于解决嵌套循环 302 | private Stack loopLabelStack = new Stack(); 303 | 304 | 305 | 306 | private Expression Statement() 307 | { 308 | switch (S.Token) 309 | { 310 | case LBRACE: 311 | return Block(); 312 | 313 | case IF: 314 | { 315 | S.NextToken(); 316 | Expression cond = ParExpression(); 317 | Expression thenpart = Statement(); 318 | Expression elsepart = null; 319 | if (S.Token == ELSE) 320 | { 321 | S.NextToken(); 322 | elsepart = Statement(); 323 | } 324 | return E.At(S.Pos).IfThenElse(cond, thenpart, elsepart); 325 | } 326 | 327 | case FOR: 328 | { 329 | S.NextToken(); 330 | 331 | Accept(LPAREN); 332 | 333 | Expression inits = S.Token == SEMI ? Expression.Empty() : GetExpression(); 334 | 335 | Accept(SEMI); 336 | 337 | Expression cond = S.Token == SEMI ? Expression.Empty() : GetExpression(); 338 | 339 | Accept(SEMI); 340 | 341 | Expression steps = S.Token == RPAREN ? Expression.Empty() : GetExpression(); 342 | 343 | Accept(RPAREN); 344 | 345 | loopLabelStack.Push(Expression.Label()); 346 | 347 | Expression body = Statement(); 348 | return E.At(S.Pos).ForLoop(inits, cond, steps, body, loopLabelStack.Pop()); 349 | 350 | } 351 | 352 | case WHILE: 353 | { 354 | S.NextToken(); 355 | 356 | Expression cond = ParExpression(); 357 | loopLabelStack.Push(Expression.Label()); 358 | Expression body = Statement(); 359 | Expression t = E.At(S.Pos).WhileLoop(cond, body, loopLabelStack.Pop()); 360 | return t; 361 | } 362 | 363 | case DO: 364 | { 365 | S.NextToken(); 366 | 367 | loopLabelStack.Push(Expression.Label()); 368 | 369 | Expression body = Statement(); 370 | 371 | Accept(WHILE); 372 | 373 | Expression cond = ParExpression(); 374 | 375 | Expression t = E.At(S.Pos).DoWhileLoop(body, cond,loopLabelStack.Pop()); 376 | 377 | return t; 378 | 379 | } 380 | 381 | case BREAK: 382 | { 383 | S.NextToken(); 384 | //应该先判断是否Peek()为空,以后在处理 385 | Expression t = E.At(S.Pos).Break(loopLabelStack.Peek()); 386 | Accept(SEMI); 387 | return t; 388 | } 389 | 390 | case RETURN: 391 | { 392 | S.NextToken(); 393 | Expression result = S.Token == SEMI ? null : VariableInitializer(); 394 | //应该先判断是否Peek()为空,以后在处理 395 | Expression t = E.At(S.Pos).Return(funcReturnStack.Peek(), result); 396 | Accept(SEMI); 397 | return t; 398 | } 399 | case ELSE: 400 | { 401 | throw ScriptCompileException.CreateSyntaxError(S.Line, S.Col, S.Token, S.TokenString); 402 | } 403 | default: 404 | { 405 | Expression t = GetExpression(); 406 | Accept(SEMI); 407 | return t; 408 | } 409 | } 410 | } 411 | 412 | 413 | //parExpression = "(" Expression ")" 414 | 415 | private Expression ParExpression() 416 | { 417 | Accept(LPAREN); 418 | 419 | Expression t = GetExpression(); 420 | 421 | Accept(RPAREN); 422 | 423 | return t; 424 | } 425 | 426 | Expression Term(int newmode) 427 | { 428 | int prevmode = mode; 429 | mode = newmode; 430 | Expression t = Term(); 431 | lastmode = mode; 432 | mode = prevmode; 433 | return t; 434 | } 435 | 436 | 437 | /* 处理一些二元操作(目前只处理了复制操作) 438 | * Expression = Expression1 [ExpressionRest] 439 | * ExpressionRest = [AssignmentOperator Expression1] 440 | * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" | "&=" | "|=" | "^=" | "%=" 441 | * Type = Type1 442 | * TypeNoParams = TypeNoParams1 443 | * StatementExpression = Expression 444 | * ConstantExpression = Expression 445 | */ 446 | 447 | private Expression Term() 448 | { 449 | Expression t = Term1(); 450 | 451 | if ((mode & LValue) != 0) //左值 452 | { 453 | mode = EXPR; 454 | Expression t1 = Term(); 455 | return E.At(S.Pos).Assign(t, t1); 456 | } 457 | else if ((mode & EXPR) != 0 && S.Token == Link) 458 | { 459 | S.NextToken(); 460 | Expression t1 = Term(); 461 | return E.At(S.Pos).LinkStr(t, t1); 462 | } 463 | else if ((mode & EXPR) != 0 && S.Token == EQ || S.Token >= PLUSEQ && S.Token <= PERCENTEQ) 464 | return TermRest(t); 465 | else 466 | return t; 467 | 468 | } 469 | private Expression TermRest(Expression t) 470 | { 471 | switch (S.Token) 472 | { 473 | case PLUSEQ: 474 | 475 | case SUBEQ: 476 | 477 | case STAREQ: 478 | 479 | case SLASHEQ: 480 | 481 | case PERCENTEQ: 482 | 483 | case AMPEQ: 484 | 485 | case BAREQ: 486 | 487 | case CARETEQ: 488 | break; 489 | 490 | default: 491 | return t; 492 | 493 | } 494 | return t; 495 | } 496 | 497 | /* 处理 ? : 三目运算符,目前不处理 498 | * Expression1 = Expression2 [Expression1Rest] 499 | * Type1 = Type2 500 | * TypeNoParams1 = TypeNoParams2 501 | */ 502 | private Expression Term1() 503 | { 504 | Expression t = Term2(); 505 | if ((mode & EXPR) != 0 & S.Token == QUES) 506 | { 507 | mode = EXPR; 508 | return Term1Rest(t); 509 | } 510 | else 511 | { 512 | return t; 513 | } 514 | } 515 | 516 | private Expression Term1Rest(Expression t) 517 | { 518 | if (S.Token == QUES) 519 | { 520 | int pos = S.Pos; 521 | S.NextToken(); 522 | Expression t1 = Term(); 523 | Accept(COLON); 524 | Expression t2 = Term1(); 525 | return E.At(pos).Conditional(t, t1, t2); 526 | } 527 | else 528 | { 529 | return t; 530 | } 531 | } 532 | 533 | 534 | // 处理二元运算 + - * / 535 | // 获取操作符左边的表达式 536 | private Expression Term2() 537 | { 538 | Expression t = Term3(); 539 | 540 | //是右值表达式 541 | if ((mode & EXPR) != 0 && IsBinaryOperator(S.Token)) 542 | { 543 | mode = EXPR; 544 | return Term2Rest(t, ExpInfo.OrPrec); 545 | } 546 | else 547 | { 548 | return t; 549 | } 550 | } 551 | //是否是二元操作符 552 | private bool IsBinaryOperator(int token) 553 | { 554 | return ExpInfo.OpPrec(token) != -1 ? true : false; 555 | } 556 | //操作数栈 557 | private Stack odStack = new Stack(); 558 | 559 | //操作符号栈 560 | private Stack opStack = new Stack(); 561 | 562 | //处理所有的二元运算,不错的算法,可以使用递推的函数调用代替,每进入下一个函数处理一段优先级,很明显,这样效率会很低,特别在"递归下降语法分析"中 563 | //而本算法会有优异的性能,通用、简单、高效、易扩展 564 | private Expression Term2Rest(Expression t, int minprec) 565 | { 566 | odStack.Push(t); //操作数进栈 567 | int topOp = ERROR; 568 | while (Prec(S.Token) >= minprec) 569 | { 570 | opStack.Push(topOp); //操作符进栈 571 | topOp = S.Token; //获取当前运算符 572 | S.NextToken(); 573 | t = Term3(); 574 | odStack.Push(t); 575 | while (odStack.Count > 0 && opStack.Count > 0 && Prec(topOp) >= Prec(S.Token)) 576 | { 577 | Expression t2 = odStack.Pop(); 578 | Expression t1 = odStack.Pop(); 579 | t = E.MakeOp(topOp, t1, t2); 580 | odStack.Push(t); 581 | topOp = opStack.Pop(); 582 | } 583 | } 584 | t = odStack.Pop(); 585 | odStack.Clear(); 586 | opStack.Clear(); 587 | return t; 588 | } 589 | 590 | private int Prec(int token) 591 | { 592 | return ExpInfo.OpPrec(token); //返回操作符的优先级数 593 | } 594 | 595 | private Expression Term3() 596 | { 597 | Expression t = null; 598 | 599 | switch (S.Token) 600 | { 601 | case PLUSPLUS: // 例如 ++i 602 | S.NextToken(); 603 | t = Term3(); 604 | t = E.At(S.Pos).PosInc(t, true); 605 | break; 606 | 607 | case SUBSUB: // 例如 --i 608 | S.NextToken(); 609 | t = Term3(); 610 | t = E.At(S.Pos).PosDec(t, true); 611 | break; 612 | 613 | case THIS: 614 | S.NextToken(); 615 | 616 | if (S.Token == EQ) 617 | { 618 | throw ScriptCompileException.CreateSyntaxError(S.Line, S.Col, S.Token, S.TokenString); 619 | } 620 | t = E.At(S.Pos).GetThisValue(); 621 | 622 | break; 623 | 624 | case FALSE: 625 | Contract.Assert(S.TokenString == "false"); 626 | t = E.At(S.Pos).Flase(); 627 | S.NextToken(); 628 | break; 629 | 630 | case TRUE: 631 | Contract.Assert(S.TokenString == "true"); 632 | t = E.At(S.Pos).True(); 633 | S.NextToken(); 634 | break; 635 | 636 | case NUMBER: //数字 637 | t = E.At(S.Pos).Number(S.TokenString); 638 | S.NextToken(); 639 | 640 | break; 641 | 642 | case STRINGLITERAL: //字符串 643 | 644 | t = E.At(S.Pos).String(S.TokenString); 645 | S.NextToken(); 646 | break; 647 | 648 | 649 | case FUNCTION: //函数 650 | 651 | S.NextToken(); 652 | 653 | t = MethodDeclaratorRest(); 654 | 655 | break; 656 | 657 | case LBRACE: 658 | 659 | t = TableInitializer(t); 660 | 661 | break; 662 | 663 | case IDENTIFIER: 664 | 665 | string ident = Ident(); 666 | 667 | if (S.Token == EQ) 668 | { 669 | mode = LValue; 670 | 671 | S.NextToken(); 672 | 673 | if (S.Token != Nil) 674 | { 675 | t = E.At(S.Pos).Select(t, ident, true); 676 | } 677 | else 678 | { 679 | t = E.At(S.Pos).Remove(t, ident); 680 | mode = EXPR; 681 | } 682 | } 683 | else 684 | { 685 | t = E.At(S.Pos).Select(t, ident, false); 686 | 687 | if (S.Token == LPAREN) 688 | { 689 | t = Arguments(t); 690 | } 691 | } 692 | break; 693 | 694 | default: 695 | throw ScriptCompileException.CreateSyntaxError(S.Line, S.Col, S.Token, S.TokenString); 696 | } 697 | while (true) 698 | { 699 | if (S.Token == DOT) 700 | { 701 | S.NextToken(); 702 | 703 | string ident = Ident(); 704 | 705 | if (S.Token == EQ) 706 | { 707 | mode = LValue; 708 | 709 | S.NextToken(); 710 | 711 | if (S.Token != Nil) 712 | { 713 | t = E.At(S.Pos).Select(t, ident, true); 714 | } 715 | else 716 | { 717 | t = E.At(S.Pos).Remove(t, ident); 718 | mode = EXPR; 719 | } 720 | } 721 | else if (S.Token == LPAREN) 722 | { 723 | Expression own = t; 724 | t = E.At(S.Pos).Select(t, ident, false); 725 | t = Arguments(own, t); 726 | } 727 | else 728 | { 729 | t = E.At(S.Pos).Select(t, ident, false); 730 | } 731 | } 732 | else if (S.Token == LPAREN) // ( 733 | { 734 | t = Arguments(t); 735 | } 736 | else if (S.Token == LBRACKET) // [ 737 | { 738 | S.NextToken(); 739 | 740 | Expression t1 = Term(); 741 | 742 | Accept(RBRACKET); 743 | 744 | if (S.Token == EQ) 745 | { 746 | mode = LValue; 747 | 748 | S.NextToken(); 749 | 750 | if (S.Token != Nil) 751 | { 752 | t = E.At(S.Pos).Select(t, t1, true); 753 | } 754 | else 755 | { 756 | t = E.At(S.Pos).Remove(t, t1); 757 | mode = EXPR; 758 | } 759 | } 760 | else if (S.Token == LPAREN) 761 | { 762 | Expression own = t; 763 | t = E.At(S.Pos).Select(t, t1, false); 764 | t = Arguments(own, t); 765 | } 766 | else 767 | { 768 | t = E.At(S.Pos).Select(t, t1, false); 769 | } 770 | } 771 | else 772 | { 773 | break; 774 | } 775 | } 776 | while ((S.Token == PLUSPLUS || S.Token == SUBSUB) && (mode & EXPR) != 0) 777 | { 778 | mode = EXPR; 779 | // t = E.At(S.Pos).Unary(S.Token == PLUSPLUS ? Tree.POSTINC : Tree.POSTDEC, t); 780 | if (S.Token == PLUSPLUS) // 后加 例如 i++; 781 | { 782 | t = E.At(S.Pos).PosInc(t, false); 783 | } 784 | else 785 | { 786 | t = E.At(S.Pos).PosDec(t, false); 787 | } 788 | S.NextToken(); 789 | } 790 | return t; 791 | } 792 | 793 | // Arguments = "(" [Expression { COMMA Expression }] ")" 794 | 795 | private List Arguments() 796 | { 797 | int pos = S.Pos; 798 | List args = new List(); 799 | if (S.Token == LPAREN) 800 | { 801 | S.NextToken(); 802 | if (S.Token != RPAREN) 803 | { 804 | args.Add(GetExpression()); 805 | while (S.Token == COMMA) 806 | { 807 | S.NextToken(); 808 | args.Add(GetExpression()); 809 | } 810 | } 811 | Accept(RPAREN); 812 | } 813 | else 814 | { 815 | throw ScriptCompileException.CreateSyntaxError(S.Line, S.Col, S.Token, S.TokenString); 816 | } 817 | return args; 818 | } 819 | private Expression Arguments(Expression own, Expression t) 820 | { 821 | int pos = S.Pos; 822 | List args = Arguments(); 823 | return E.At(pos).InvokeFunction(own, t, args); 824 | } 825 | 826 | 827 | private Expression Arguments(Expression t) 828 | { 829 | int pos = S.Pos; 830 | List args = Arguments(); 831 | return E.At(pos).InvokeFunction(t, args); 832 | } 833 | //是否是左值操作符 834 | private bool IsLOperator(int p) 835 | { 836 | switch (S.Token) 837 | { 838 | case EQ: 839 | 840 | case PLUSEQ: 841 | 842 | case SUBEQ: 843 | 844 | case STAREQ: 845 | 846 | case SLASHEQ: 847 | 848 | case PERCENTEQ: 849 | 850 | case AMPEQ: 851 | 852 | case BAREQ: 853 | 854 | case CARETEQ: 855 | return true; 856 | 857 | default: 858 | return false; 859 | } 860 | } 861 | 862 | private Expression GetExpression() 863 | { 864 | return Term(EXPR); 865 | } 866 | 867 | // FormalParameters = "(" [FormalParameter {"," FormalParameter}] ")" 868 | private TupleStruct FormalParameters() 869 | { 870 | int count = 0; 871 | bool isUncertainParameters = false; 872 | 873 | Accept(LPAREN); // ( 874 | 875 | if (S.Token != RPAREN) // ) 876 | { 877 | isUncertainParameters = FormalParameter(); //处理一个参数 878 | 879 | if (isUncertainParameters == false) 880 | { 881 | count++; 882 | while (S.Token == COMMA) 883 | { 884 | S.NextToken(); 885 | 886 | isUncertainParameters = FormalParameter(); //处理一个参数 887 | 888 | if (!isUncertainParameters) count++; 889 | 890 | else break; 891 | } 892 | } 893 | } 894 | Accept(RPAREN); // ) 895 | 896 | return new TupleStruct() { First = count, Second = isUncertainParameters }; 897 | 898 | } 899 | 900 | private bool FormalParameter() 901 | { 902 | if (S.Token == IDENTIFIER) //标识符 903 | { 904 | Instructor.CompileIndexStack.AddSymbolVar(S.TokenString); 905 | 906 | S.NextToken(); 907 | 908 | return false; 909 | } 910 | else if (S.Token == UntPar) 911 | { 912 | Instructor.CompileIndexStack.AddSymbolVar("args"); 913 | S.NextToken(); 914 | return true; 915 | } 916 | else 917 | { 918 | throw ScriptCompileException.CreateSyntaxError(S.Line, S.Col, S.Token, S.TokenString); 919 | } 920 | } 921 | } 922 | } 923 | -------------------------------------------------------------------------------- /src/Parse/Scanner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScriptInterpreter.Util; 3 | using System.Diagnostics; 4 | 5 | 6 | namespace ScriptInterpreter.Parse 7 | { 8 | public sealed class Scanner : Tokens 9 | { 10 | private int _token; 11 | private int line; 12 | private int col; 13 | 14 | public int Line 15 | { 16 | get { return line; } 17 | } 18 | public int Col 19 | { 20 | get { return col; } 21 | } 22 | private string tokenStr; 23 | 24 | public string TokenString 25 | { 26 | get { return tokenStr; } 27 | } 28 | 29 | int _radix; 30 | 31 | 32 | public int Token 33 | { 34 | get { return _token; } 35 | } 36 | 37 | private char[] sbuf = new char[128]; 38 | private int sp; 39 | 40 | private Keywords keywords; 41 | 42 | 43 | private string _buf; 44 | private int bp; 45 | private char ch; 46 | 47 | 48 | public bool IsTableValueKey() 49 | { 50 | if (_token == IDENTIFIER || _token == STRINGLITERAL) 51 | { 52 | int bp = this.bp; 53 | 54 | char ch = _buf[bp]; 55 | 56 | while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') 57 | { 58 | bp++; 59 | 60 | if (bp >= Buflen - 1) return false; 61 | 62 | ch = _buf[bp]; 63 | } 64 | if (ch == ':') return true; 65 | 66 | return false; 67 | } 68 | return false; 69 | } 70 | 71 | 72 | 73 | private int Buflen 74 | { 75 | get { return _buf.Length; } 76 | } 77 | 78 | public int Pos 79 | { 80 | get { return bp; } 81 | } 82 | 83 | 84 | public Scanner() 85 | { 86 | keywords = new Keywords(); 87 | } 88 | internal void InputString(string commandString) 89 | { 90 | _buf = commandString + EOI; 91 | 92 | line = 1; 93 | col = 0; 94 | bp = -1; 95 | 96 | ScanChar();//检查字符,并读入。 97 | NextToken();//读入下一个标示符。 98 | } 99 | 100 | public void Accept(char tokenchar) 101 | { 102 | if (ch == tokenchar) 103 | { 104 | ScanChar(); 105 | } 106 | else 107 | { 108 | //语法错误处理 109 | Debug.WriteLine("语法错误处理"); 110 | } 111 | } 112 | 113 | 114 | public void NextToken() 115 | { 116 | sp = 0; //注意,每次移动一个标识符时,标志符缓冲区要清掉 117 | tokenStr = null; //清掉 118 | while (true) 119 | { 120 | switch (ch) 121 | { 122 | case ' ': //空格 123 | 124 | case TAB: // tab 键 水平平移 125 | 126 | case FF: //换页 127 | 128 | case CR: //回车 129 | 130 | case LF: //换行 131 | ScanChar(); 132 | break; 133 | case 'A': 134 | 135 | case 'B': 136 | 137 | case 'C': 138 | 139 | case 'D': 140 | 141 | case 'E': 142 | 143 | case 'F': 144 | 145 | case 'G': 146 | 147 | case 'H': 148 | 149 | case 'I': 150 | 151 | case 'J': 152 | 153 | case 'K': 154 | 155 | case 'L': 156 | 157 | case 'M': 158 | 159 | case 'N': 160 | 161 | case 'O': 162 | 163 | case 'P': 164 | 165 | case 'Q': 166 | 167 | case 'R': 168 | 169 | case 'S': 170 | 171 | case 'T': 172 | 173 | case 'U': 174 | 175 | case 'V': 176 | 177 | case 'W': 178 | 179 | case 'X': 180 | 181 | case 'Y': 182 | 183 | case 'Z': 184 | 185 | case 'a': 186 | 187 | case 'b': 188 | 189 | case 'c': 190 | 191 | case 'd': 192 | 193 | case 'e': 194 | 195 | case 'f': 196 | 197 | case 'g': 198 | 199 | case 'h': 200 | 201 | case 'i': 202 | 203 | case 'j': 204 | 205 | case 'k': 206 | 207 | case 'l': 208 | 209 | case 'm': 210 | 211 | case 'n': 212 | 213 | case 'o': 214 | 215 | case 'p': 216 | 217 | case 'q': 218 | 219 | case 'r': 220 | 221 | case 's': 222 | 223 | case 't': 224 | 225 | case 'u': 226 | 227 | case 'v': 228 | 229 | case 'w': 230 | 231 | case 'x': 232 | 233 | case 'y': 234 | 235 | case 'z': 236 | 237 | // case '$': 238 | 239 | case '_': 240 | ScanIdent(); 241 | return; 242 | 243 | case '0': 244 | ScanChar(); 245 | if (ch == 'x' || ch == 'X') 246 | { 247 | ScanChar(); 248 | //if (digit(16) < 0) 249 | //{ 250 | // lexError("invalid.hex.number"); 251 | //} 252 | //scanNumber(16); 253 | } 254 | else 255 | { 256 | PutChar('0'); 257 | ScanNumber(8); 258 | } 259 | return; 260 | 261 | case '1': 262 | 263 | case '2': 264 | 265 | case '3': 266 | 267 | case '4': 268 | 269 | case '5': 270 | 271 | case '6': 272 | 273 | case '7': 274 | 275 | case '8': 276 | 277 | case '9': 278 | ScanNumber(10); 279 | return; 280 | case '.': 281 | ScanChar(); 282 | if(ch=='.') //还是点的话就是字符串的链接 283 | { 284 | ScanChar(); 285 | if (ch == '.') 286 | { 287 | 288 | ScanChar(); 289 | _token = UntPar; 290 | } 291 | else _token = Link; 292 | } 293 | else _token = DOT; 294 | return; 295 | case ',': 296 | ScanChar(); 297 | _token = COMMA; 298 | return; 299 | 300 | case ';': 301 | ScanChar(); 302 | _token = SEMI; 303 | return; 304 | 305 | case '(': 306 | ScanChar(); 307 | _token = LPAREN; 308 | return; 309 | 310 | case ')': 311 | ScanChar(); 312 | _token = RPAREN; 313 | return; 314 | 315 | case '[': 316 | ScanChar(); 317 | _token = LBRACKET; 318 | return; 319 | 320 | case ']': 321 | ScanChar(); 322 | _token = RBRACKET; 323 | return; 324 | 325 | case '{': 326 | ScanChar(); 327 | _token = LBRACE; 328 | return; 329 | 330 | case '}': 331 | ScanChar(); 332 | _token = RBRACE; 333 | return; 334 | 335 | case '/': 336 | ScanChar(); 337 | if (ch == '/') 338 | { 339 | do 340 | { 341 | ScanChar(); 342 | } while (ch != CR && ch != LF); //跳过一行 343 | break; //跳出switch 344 | } 345 | else if (ch == '*') //段落注释 346 | { 347 | SkipComment(); //跳过注释 348 | 349 | // Accept('/'); 350 | 351 | if (ch == '/') 352 | { 353 | ScanChar(); 354 | } 355 | else 356 | { 357 | //Error 358 | throw new NotSupportedException(); 359 | } 360 | break; //跳出switch 361 | } 362 | else if (ch == '=') 363 | { 364 | _token = SLASHEQ; 365 | ScanChar(); 366 | } 367 | else 368 | { 369 | _token = SLASH; 370 | return; 371 | } 372 | return; 373 | case '\'': //接受字符串 374 | ScanChar(); 375 | while (ch != '\'' && ch != CR && ch != LF && bp < Buflen) 376 | ScanLitChar(); 377 | 378 | if (ch == '\'') 379 | { 380 | _token = STRINGLITERAL; 381 | ScanChar(); 382 | } 383 | else 384 | { 385 | // Error 386 | } 387 | tokenStr = new string(sbuf, 0, sp); 388 | return; 389 | 390 | case '\"': //接受字符串 391 | ScanChar(); 392 | while (ch != '\"' && ch != CR && ch != LF && bp < Buflen) 393 | ScanLitChar(); 394 | 395 | if (ch == '\"') 396 | { 397 | _token = STRINGLITERAL; 398 | ScanChar(); 399 | } 400 | else 401 | { 402 | // Error 403 | } 404 | tokenStr = new string(sbuf, 0, sp); 405 | return; 406 | default: 407 | if (IsSpecial(ch)) 408 | { 409 | ScanOperator(); 410 | } 411 | else if (bp == Buflen || ch == EOI && bp + 1 == Buflen) 412 | { 413 | _token = EOF; 414 | } 415 | else if (!IsIdentifierPart(ch)) 416 | { 417 | tokenStr = new string(sbuf, 0, sp); 418 | _token = keywords.key(tokenStr); 419 | return; 420 | } 421 | return; 422 | } 423 | 424 | } 425 | } 426 | 427 | // 读取字符和字符串中的下一个各种命令标志 428 | private void ScanLitChar() 429 | { 430 | if (ch == '\\') 431 | { 432 | if (_buf[bp + 1] == '\\' && 0 != bp) 433 | { 434 | bp++; 435 | col++; 436 | PutChar('\\'); 437 | ScanChar(); 438 | } 439 | else 440 | { 441 | ScanChar(); 442 | switch (ch) 443 | { 444 | case '0': 445 | 446 | case '1': 447 | 448 | case '2': 449 | 450 | case '3': 451 | 452 | case '4': 453 | 454 | case '5': 455 | 456 | case '6': 457 | 458 | case '7': 459 | char leadch = ch; 460 | int oct = Digit(8); 461 | ScanChar(); 462 | if ('0' <= ch && ch <= '7') 463 | { 464 | oct = oct * 8 + Digit(8); 465 | ScanChar(); 466 | if (leadch <= '3' && '0' <= ch && ch <= '7') 467 | { 468 | oct = oct * 8 + Digit(8); 469 | ScanChar(); 470 | } 471 | } 472 | PutChar((char)oct); 473 | break; 474 | 475 | case 'b': 476 | PutChar('\b');//各种字符串中的表示符号的处理方法 477 | ScanChar(); 478 | break; 479 | 480 | case 't': 481 | PutChar('\t'); 482 | ScanChar(); 483 | break; 484 | 485 | case 'n': 486 | PutChar('\n'); 487 | ScanChar(); 488 | break; 489 | 490 | case 'f': 491 | PutChar('\f'); 492 | ScanChar(); 493 | break; 494 | 495 | case 'r': 496 | PutChar('\r'); 497 | ScanChar(); 498 | break; 499 | 500 | case '\'': 501 | PutChar('\''); 502 | ScanChar(); 503 | break; 504 | 505 | case '\"': 506 | PutChar('\"'); 507 | ScanChar(); 508 | break; 509 | 510 | case '\\': 511 | PutChar('\\'); 512 | ScanChar(); 513 | break; 514 | 515 | default: 516 | throw new NotImplementedException(); 517 | } 518 | } 519 | } 520 | else if (bp != Buflen) 521 | { 522 | PutChar(ch); 523 | ScanChar(); 524 | } 525 | } 526 | 527 | private int Digit(int p) 528 | { 529 | throw new NotImplementedException(); 530 | } 531 | 532 | private void SkipComment() 533 | { 534 | while (bp < Buflen) 535 | { 536 | switch (ch) 537 | { 538 | case '*': 539 | ScanChar(); 540 | if (ch == '/') 541 | return; 542 | break; 543 | 544 | default: 545 | ScanChar(); 546 | break; 547 | 548 | } 549 | } 550 | } 551 | 552 | private void ScanNumber(int radix) 553 | { 554 | _radix = radix; 555 | 556 | int digitRadix = (radix <= 10) ? 10 : 16; 557 | 558 | while (Char.IsDigit(ch) == true) 559 | { 560 | PutChar(ch); 561 | ScanChar(); 562 | } 563 | if (radix <= 10 && ch == '.') 564 | { 565 | PutChar(ch); 566 | ScanChar(); 567 | ScanFractionAndSuffix(); 568 | } 569 | else if (radix <= 10 && (ch == 'e' || ch == 'E' || ch == 'f' || ch == 'F' || ch == 'd' || ch == 'D')) 570 | { 571 | // scanFractionAndSuffix(); 572 | } 573 | else 574 | { 575 | if (ch == 'l' || ch == 'L') 576 | { 577 | ScanChar(); 578 | //token = LONGLITERAL; 579 | } 580 | else 581 | { 582 | 583 | } 584 | } 585 | _token = NUMBER; 586 | tokenStr = new string(sbuf, 0, sp); 587 | } 588 | 589 | 590 | //读取浮点数的小数部分和f,d后缀。 591 | private void ScanFractionAndSuffix() 592 | { 593 | while (Char.IsDigit(ch) == true) 594 | { 595 | PutChar(ch); 596 | ScanChar(); 597 | } 598 | } 599 | 600 | /// 601 | /// 读取标识符 602 | /// 603 | private void ScanIdent() 604 | { 605 | do 606 | { 607 | if (sp == sbuf.Length) 608 | PutChar(ch); 609 | else 610 | sbuf[sp++] = ch; 611 | 612 | ScanChar(); 613 | 614 | switch (ch) 615 | { 616 | case 'A': 617 | 618 | case 'B': 619 | 620 | case 'C': 621 | 622 | case 'D': 623 | 624 | case 'E': 625 | 626 | case 'F': 627 | 628 | case 'G': 629 | 630 | case 'H': 631 | 632 | case 'I': 633 | 634 | case 'J': 635 | 636 | case 'K': 637 | 638 | case 'L': 639 | 640 | case 'M': 641 | 642 | case 'N': 643 | 644 | case 'O': 645 | 646 | case 'P': 647 | 648 | case 'Q': 649 | 650 | case 'R': 651 | 652 | case 'S': 653 | 654 | case 'T': 655 | 656 | case 'U': 657 | 658 | case 'V': 659 | 660 | case 'W': 661 | 662 | case 'X': 663 | 664 | case 'Y': 665 | 666 | case 'Z': 667 | 668 | case 'a': 669 | 670 | case 'b': 671 | 672 | case 'c': 673 | 674 | case 'd': 675 | 676 | case 'e': 677 | 678 | case 'f': 679 | 680 | case 'g': 681 | 682 | case 'h': 683 | 684 | case 'i': 685 | 686 | case 'j': 687 | 688 | case 'k': 689 | 690 | case 'l': 691 | 692 | case 'm': 693 | 694 | case 'n': 695 | 696 | case 'o': 697 | 698 | case 'p': 699 | 700 | case 'q': 701 | 702 | case 'r': 703 | 704 | case 's': 705 | 706 | case 't': 707 | 708 | case 'u': 709 | 710 | case 'v': 711 | 712 | case 'w': 713 | 714 | case 'x': 715 | 716 | case 'y': 717 | 718 | case 'z': 719 | 720 | // case '$': 721 | 722 | case '_': 723 | 724 | case '0': 725 | 726 | case '1': 727 | 728 | case '2': 729 | 730 | case '3': 731 | 732 | case '4': 733 | 734 | case '5': 735 | 736 | case '6': 737 | 738 | case '7': 739 | 740 | case '8': 741 | 742 | case '9': 743 | break; 744 | 745 | default: 746 | if (!IsIdentifierPart(ch) || bp >= Buflen) 747 | { 748 | tokenStr = new string(sbuf, 0, sp); 749 | _token = keywords.key(tokenStr); 750 | return; 751 | } 752 | break; 753 | } 754 | } while (true); 755 | 756 | } 757 | 758 | /// 759 | /// 读取操作符 760 | /// 761 | private void ScanOperator() 762 | { 763 | while (true) 764 | { 765 | PutChar(ch); 766 | string newname = new string(sbuf, 0, sp); 767 | if (keywords.key(newname) == IDENTIFIER) 768 | { 769 | sp--; 770 | break; 771 | } 772 | tokenStr = newname; 773 | _token = keywords.key(newname); 774 | ScanChar(); 775 | if (!IsSpecial(ch)) //不是 776 | break; 777 | } 778 | } 779 | 780 | // 如果是操作符得一部分,则返回true,用于判断操作符。 781 | public bool IsSpecial(char ch) 782 | { 783 | switch (ch) 784 | { 785 | case '!': 786 | 787 | case '%': 788 | 789 | case '&': 790 | 791 | case '*': 792 | 793 | case '?': 794 | 795 | case '+': 796 | 797 | case '-': 798 | 799 | case ':': 800 | 801 | case '<': 802 | 803 | case '=': 804 | 805 | case '>': 806 | 807 | case '^': 808 | 809 | case '|': 810 | 811 | case '~': 812 | return true; 813 | 814 | default: 815 | return false; 816 | 817 | } 818 | } 819 | 820 | private bool IsIdentifierPart(char ch) 821 | { 822 | return false; //简单处理 823 | } 824 | 825 | private void PutChar(char ch) 826 | { 827 | if (sp == sbuf.Length) 828 | { 829 | Array.Resize(ref sbuf, sbuf.Length * 2); 830 | } 831 | sbuf[sp++] = ch; 832 | } 833 | private void ScanChar() 834 | { 835 | bp++; 836 | ch = _buf[bp]; 837 | switch (ch) 838 | { 839 | case '\r': //回车 840 | col = 0; 841 | line++; 842 | break; 843 | case '\n': //换行 844 | 845 | if (bp == 0 || _buf[bp - 1] != '\r') 846 | { 847 | col = 0; 848 | line++; 849 | } 850 | break; 851 | 852 | case '\t': //制表符 853 | col = (col / TabInc * TabInc) + TabInc; 854 | break; 855 | 856 | default: 857 | col++; 858 | break; 859 | 860 | } 861 | } 862 | } 863 | } 864 | 865 | -------------------------------------------------------------------------------- /src/Parse/Tokens.cs: -------------------------------------------------------------------------------- 1 | namespace ScriptInterpreter.Parse 2 | { 3 | public class Tokens 4 | { 5 | protected Tokens() { } 6 | 7 | /** 8 | * Tabulator column increment. 9 | */ 10 | public const int TabInc = 8; //tab 键水平移动的字符数 11 | 12 | /** 13 | * Tabulator character. 14 | */ 15 | public const char BS = (char)8; //退格 16 | 17 | public const char TAB = (char)9; //tab键 水平制表符 '\t' 18 | 19 | 20 | public const char SP = ' '; //空格 21 | /** 22 | * Line feed character. 23 | */ 24 | public const char LF = (char)10; //换行键 '\n' 25 | 26 | 27 | public const char CR = (char)13; //回车键 '\r' 28 | 29 | /** 30 | * Form feed character. 31 | */ 32 | 33 | //换页键 34 | public const char FF = (char)12; 35 | 36 | /** 37 | * Carriage return character. 38 | */ 39 | 40 | 41 | /** 42 | * End of input character. Used as a sentinel to denote the 43 | * character one beyond the last defined character in a 44 | * source file. 45 | */ 46 | public const char EOI = (char)26; 47 | 48 | public const int EOF = 0; 49 | public const int ERROR = EOF + 1; 50 | public const int IDENTIFIER = ERROR + 1; 51 | 52 | public const int PLUS = IDENTIFIER + 1; // "+" 53 | public const int SUB = PLUS + 1; // "-" 54 | public const int BANG = SUB + 1; // "!" 55 | public const int PERCENT = BANG + 1; // "%" 56 | public const int STAR = PERCENT + 1; // * 57 | public const int SLASH = STAR + 1; // / 58 | public const int GT = SLASH + 1; // ">" 59 | public const int LT = GT + 1; // "<" 60 | public const int QUES = LT + 1; // ? 61 | public const int COLON = QUES + 1; // : 62 | public const int EQ = COLON + 1; // "=" 63 | public const int PLUSPLUS = EQ + 1; // "++" 64 | public const int SUBSUB = PLUSPLUS + 1; // "--" 65 | public const int EQEQ = SUBSUB + 1; // "==" 66 | public const int LTEQ = EQEQ + 1; // "<=" 67 | public const int GTEQ = LTEQ + 1; // ">=" 68 | public const int BANGEQ = GTEQ + 1; // "!=" 69 | 70 | 71 | public const int PLUSEQ = BANGEQ + 1; // "+=" 72 | public const int SUBEQ = PLUSEQ + 1; // "-=" 73 | public const int STAREQ = SUBEQ + 1; // "*=" 74 | public const int SLASHEQ = STAREQ + 1; // "/=" 75 | public const int AMPEQ = SLASHEQ + 1; // "&=" 76 | public const int BAREQ = AMPEQ + 1; // "|=" 77 | public const int CARETEQ = BAREQ + 1; // "^=" 78 | public const int PERCENTEQ = CARETEQ + 1; // "%=" 79 | 80 | public const int GLOBAL = PERCENTEQ + 1; // global 81 | public const int LOCAL = GLOBAL + 1; //local 82 | public const int FUNCTION = LOCAL + 1; //function 83 | public const int NUMBER = FUNCTION + 1; 84 | public const int Nil = NUMBER + 1; // nil 85 | 86 | public const int THIS = Nil + 1; // this 87 | public const int FALSE = THIS + 1; //false 88 | public const int TRUE = FALSE + 1; //true 89 | public const int BREAK = FALSE + 1; //break 90 | public const int CONTINUE = BREAK + 1; // continue 91 | public const int STRINGLITERAL = CONTINUE + 1; // string 92 | public const int Link = STRINGLITERAL + 1; // .. 93 | 94 | public const int UntPar = Link + 1; // ... 95 | 96 | public const int CHAR = UntPar + 1; //char 97 | public const int DO = CHAR + 1; //do 98 | public const int ELSE = DO + 1; 99 | public const int FOR = ELSE + 1; 100 | public const int IF = FOR + 1; //if 101 | public const int INT = IF + 1; 102 | public const int RETURN = INT + 1; //return 103 | public const int WHILE = RETURN + 1; //while 104 | 105 | public const int DOT = WHILE + 1; // . 106 | public const int COMMA = DOT + 1; // , 107 | public const int SEMI = COMMA + 1; // ; 108 | public const int LPAREN = SEMI + 1; // ( 109 | public const int RPAREN = LPAREN + 1; // ) 110 | public const int LBRACKET = RPAREN + 1; //[ 111 | public const int RBRACKET = LBRACKET + 1; //] 112 | public const int LBRACE = RBRACKET + 1; // { 113 | public const int RBRACE = LBRACE + 1; // } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/RunTime/Instructor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.Contracts; 5 | using ScriptInterpreter.Util; 6 | using ScriptInterpreter.Parse; 7 | 8 | namespace ScriptInterpreter.RunTime 9 | { 10 | public static class Instructor 11 | { 12 | internal class CompileStack 13 | { 14 | public const int UPVALUE_OFFSET = 2; 15 | 16 | /// 17 | /// 有区域范围的符号表 18 | /// 19 | private List> _blockSymbolTable = new List>(); 20 | 21 | private Stack _indexStack = new Stack(); 22 | 23 | private int _symbolcount; 24 | 25 | public int IndexTop 26 | { 27 | get { return _symbolcount; } 28 | 29 | set { _symbolcount = value; } 30 | } 31 | 32 | public CompileStack() 33 | { 34 | } 35 | 36 | public void EnterBlock() 37 | { 38 | Dictionary symbolTable = new Dictionary(); 39 | 40 | _blockSymbolTable.Add(symbolTable); 41 | } 42 | 43 | public int OutBlock() 44 | { 45 | int count = _blockSymbolTable[_blockSymbolTable.Count - 1].Count; 46 | IndexTop -= count; 47 | 48 | _blockSymbolTable.RemoveAt(_blockSymbolTable.Count - 1); 49 | 50 | return count; 51 | } 52 | 53 | public void AddSymbolVar(string localName) 54 | { 55 | Dictionary symbolTable = _blockSymbolTable[_blockSymbolTable.Count -1]; 56 | 57 | int at; 58 | 59 | if (symbolTable.TryGetValue(localName, out at) == false) //不存在 60 | { 61 | symbolTable.Add(localName, IndexTop++); 62 | } 63 | else 64 | { 65 | throw ScriptCompileException.CreateContentExist(localName); 66 | } 67 | } 68 | 69 | public int GetSymbolIndex(string localName) 70 | { 71 | int currentIndex = _indexStack.Peek() + 1; 72 | 73 | Dictionary symbolTable; 74 | 75 | int resoult; 76 | 77 | for (int i = _blockSymbolTable.Count - 1; i >= 0; --i) 78 | { 79 | symbolTable = _blockSymbolTable[i]; 80 | 81 | if (symbolTable.TryGetValue(localName, out resoult) == true) 82 | { 83 | if (resoult >= currentIndex) 84 | { 85 | return resoult - currentIndex; 86 | } 87 | else 88 | { 89 | return -resoult - UPVALUE_OFFSET; 90 | } 91 | } 92 | } 93 | return -1; 94 | } 95 | 96 | internal void LogIndex() 97 | { 98 | _indexStack.Push(IndexTop++); //记录下函数位置 99 | 100 | EnterBlock(); 101 | } 102 | 103 | internal void PopIndex() 104 | { 105 | OutBlock(); 106 | _indexStack.Pop(); 107 | --IndexTop; 108 | } 109 | internal void CheckClear() 110 | { 111 | Contract.Assert(_indexStack.Count == 0); 112 | Contract.Assert(_blockSymbolTable.Count == 0); 113 | Contract.Assert(_symbolcount == 0); 114 | } 115 | 116 | /// 117 | /// 清理编译符号表等信息 118 | /// 119 | internal void Clear() 120 | { 121 | _indexStack.Clear(); 122 | _blockSymbolTable.Clear(); 123 | _symbolcount = 0; 124 | } 125 | } 126 | 127 | private static CompileStack comStack = new CompileStack(); 128 | 129 | internal static CompileStack CompileIndexStack 130 | { 131 | get { return comStack; } 132 | } 133 | 134 | public static ConstantExpression GetConstantExpression(this bool boolValue) 135 | { 136 | return Expression.Constant(boolValue); 137 | } 138 | public static ConstantExpression GetConstantExpression(this int intValue) 139 | { 140 | return Expression.Constant(intValue); 141 | } 142 | public static ConstantExpression GetConstantExpression(this string strValue) 143 | { 144 | return Expression.Constant(strValue); 145 | } 146 | public static ConstantExpression GetConstantExpression(this double numValue) 147 | { 148 | return Expression.Constant(numValue); 149 | } 150 | 151 | public static ConstantExpression GetConstantExpression(this Action numValue) 152 | { 153 | return Expression.Constant(numValue); 154 | } 155 | 156 | public static ConstantExpression GetConstantExpression(this ScriptObject obj) 157 | { 158 | return Expression.Constant(obj); 159 | } 160 | 161 | 162 | public static Expression GetGlobalVarExpression(string varName, bool isLvalue) 163 | { 164 | 165 | if (isLvalue == true) //左值 166 | { 167 | return Expression.Call(typeof(Instructor).GetMethod("CreateGlobalVar"), varName.GetConstantExpression()); 168 | } 169 | else 170 | { 171 | return Expression.Call(typeof(Instructor).GetMethod("GetGlobalVar"), varName.GetConstantExpression()); 172 | } 173 | 174 | } 175 | 176 | private static Expression GetUpVarExpression(string name,int offset) 177 | { 178 | //修正偏移 179 | offset = -offset - CompileStack.UPVALUE_OFFSET; 180 | 181 | //从哈希改为List,考虑到一般情况,UpValue个数不会太多 182 | List> upValues = RunEnvironment.Instance.Parser.UpValueStack.Peek(); 183 | 184 | int i; 185 | 186 | for (i = 0; i < upValues.Count; i++) 187 | { 188 | if (upValues[i].Key == name) 189 | { 190 | break; 191 | } 192 | } 193 | if (i >= upValues.Count) 194 | { 195 | upValues.Add(new KeyValuePair(name,offset)); 196 | } 197 | return Expression.Call(typeof(Instructor).GetMethod("GetUpVar"), i.GetConstantExpression()); 198 | } 199 | 200 | public static Expression GetLocalVarExpression(int offset) 201 | { 202 | return Expression.Call(typeof(Instructor).GetMethod("GetLocalVar"), offset.GetConstantExpression()); 203 | } 204 | 205 | public static Expression ConverListToBlock(List i) 206 | { 207 | return Expression.Block(i); 208 | } 209 | 210 | 211 | /// 212 | /// 从当前栈获得对象 213 | /// 214 | /// 215 | /// 216 | public static ScriptObject GetLocalVar(int offset) 217 | { 218 | return RunEnvironment.Instance.LocalStack.GetStackVar(offset); 219 | } 220 | 221 | public static ScriptObject GetUpVar(int offset) 222 | { 223 | return RunEnvironment.Instance.LocalStack.GetUpVar(offset); 224 | } 225 | 226 | public static ScriptObject GetGlobalVar(string name) 227 | { 228 | ScriptObject global = RunEnvironment.Instance.Global; 229 | return Select(global, name); 230 | } 231 | 232 | 233 | public static ScriptObject CreateGlobalVar(string name) 234 | { 235 | ScriptObject global = RunEnvironment.Instance.Global; 236 | return SelectOrCreate(global,name); 237 | 238 | } 239 | 240 | public static ScriptObject AssignVar(ScriptObject x, ScriptObject y) 241 | { 242 | x.Type = y.Type; 243 | x.Value = y.Value; 244 | return x; 245 | } 246 | 247 | public static ScriptObject LinkStr(ScriptObject x, ScriptObject y) 248 | { 249 | if (( x.Type == ValueType.STRING || x.Type == ValueType.NUMBER )&&( y.Type == ValueType.STRING || y.Type == ValueType.NUMBER )) 250 | { 251 | return ScriptObject.CreateString(x.GetString() + y.GetString()); 252 | } 253 | throw new Exception("执行无法链接操作"); 254 | } 255 | 256 | /// 257 | /// 从 table中获取属性 258 | /// 259 | public static Expression GetVarFromTable(Expression t, string ident, bool isLvalue) 260 | { 261 | if (isLvalue == true) 262 | { 263 | return Expression.Call(typeof(Instructor).GetMethod("SelectOrCreate"), t, ident.GetConstantExpression()); 264 | } 265 | else 266 | { 267 | return Expression.Call(typeof(Instructor).GetMethod("Select"), t, ident.GetConstantExpression()); 268 | } 269 | } 270 | 271 | /// 272 | /// 通过下标从 table中获取属性 273 | /// 274 | internal static Expression GetVarFromTable(Expression t, Expression index, bool isLvalue) 275 | { 276 | if (isLvalue == true) 277 | { 278 | return Expression.Call(typeof(Instructor).GetMethod("IndexofOrCreate"), t, index); 279 | } 280 | else 281 | { 282 | return Expression.Call(typeof(Instructor).GetMethod("Indexof"), t, index); 283 | } 284 | } 285 | 286 | /// 287 | /// 获得变量 288 | /// 289 | /// 290 | /// 291 | /// 292 | public static Expression GetVarByName(string name, bool isLvalue) 293 | { 294 | int offset; 295 | 296 | if ((offset = Instructor.CompileIndexStack.GetSymbolIndex(name)) >= 0) 297 | { 298 | return GetLocalVarExpression(offset); 299 | } 300 | else if (offset == -1) 301 | { 302 | return GetGlobalVarExpression(name, isLvalue); 303 | } 304 | return GetUpVarExpression(name,offset); 305 | } 306 | 307 | 308 | /// 309 | /// 回收此变量的空间 310 | /// 311 | /// 312 | /// 313 | /// 314 | public static Expression RemoveVarByName(string name) 315 | { 316 | int offset; 317 | 318 | if ((offset = Instructor.CompileIndexStack.GetSymbolIndex(name)) != -1) 319 | { 320 | return Expression.Call(typeof(Instructor).GetMethod("ClearStackVarAt"), offset.GetConstantExpression()); 321 | } 322 | return Expression.Call(typeof(Instructor).GetMethod("ClearTableFileld"), RunEnvironment.Instance.Global.GetConstantExpression(), name.GetConstantExpression()); 323 | } 324 | /// 325 | /// 移除此表中的制定字段 326 | /// 327 | public static Expression RemoveVarFromTable(Expression t, string name) 328 | { 329 | return Expression.Call(typeof(Instructor).GetMethod("ClearTableFileld"), t, name.GetConstantExpression()); 330 | } 331 | public static Expression RemoveVarFromTable(Expression t, Expression index) 332 | { 333 | return Expression.Call(typeof(Instructor).GetMethod("ClearTableItem"), t, index); 334 | } 335 | /// 336 | /// 从表达式结果获得条件需要的bool变量 337 | /// 338 | /// 339 | /// 340 | public static Expression GetCondition(Expression t) 341 | { 342 | return Expression.Call(typeof(Instructor).GetMethod("ConverScrObjToBool"), t); 343 | } 344 | 345 | 346 | /// 347 | /// 根据对象判断其条件属性 348 | /// 349 | /// 350 | /// 351 | public static bool ConverScrObjToBool(ScriptObject obj) 352 | { 353 | if(obj.Type == ValueType.NIL) // nil 为false 354 | { 355 | return false; 356 | } 357 | if (obj.Type == ValueType.BOOLEAN) 358 | { 359 | return obj.Value.Boolean; 360 | } 361 | return true; 362 | } 363 | 364 | 365 | /// 366 | /// 从 own 中选择 filed 字段,没有就创建一个新的 367 | /// 368 | public static ScriptObject SelectOrCreate(ScriptObject own, string filed) 369 | { 370 | return own.GetOrCreateFileld(filed); 371 | } 372 | 373 | public static ScriptObject IndexofOrCreate(ScriptObject own, ScriptObject index) 374 | { 375 | return own.GetOrCreateFileld(index); 376 | } 377 | 378 | /// 379 | /// 从 own 返回 filed 字段,没有就为nil 380 | /// 381 | public static ScriptObject Select(ScriptObject own, string filed) 382 | { 383 | return own.GetFileld(filed); 384 | } 385 | 386 | public static ScriptObject Indexof(ScriptObject own, ScriptObject index) 387 | { 388 | return own.GetFileld(index); 389 | } 390 | 391 | 392 | /// 393 | /// 将数值前加1,即 ++i; 394 | /// 395 | /// 396 | /// 397 | public static ScriptObject IncPos(ScriptObject t) 398 | { 399 | Contract.Assert(t.Type == ValueType.NUMBER); 400 | ++t.Value.Number; 401 | return t; 402 | } 403 | 404 | 405 | /// 406 | /// 将数值变量后加1,即 i++; 407 | /// 408 | /// 409 | /// 410 | public static ScriptObject PosInc(ScriptObject t) 411 | { 412 | Contract.Assert(t.Type == ValueType.NUMBER); 413 | ScriptObject newobj = ScriptObject.CreateNum(t.Value.Number); 414 | t.Value.Number++; 415 | return newobj; 416 | } 417 | 418 | 419 | /// 420 | /// 将数值前减1,即 --i; 421 | /// 422 | /// 423 | /// 424 | public static ScriptObject DecPos(ScriptObject t) 425 | { 426 | Contract.Assert(t.Type == ValueType.NUMBER); 427 | --t.Value.Number; 428 | return t; 429 | } 430 | 431 | /// 432 | /// 将数值后减1,即 i--; 433 | /// 434 | /// 435 | /// 436 | public static ScriptObject PosDec(ScriptObject t) 437 | { 438 | Contract.Assert(t.Type == ValueType.NUMBER); 439 | ScriptObject newobj = ScriptObject.CreateNum(t.Value.Number); 440 | t.Value.Number--; 441 | return newobj; 442 | } 443 | 444 | 445 | /// 446 | /// 将字段加入全局变量中 447 | /// 448 | /// 449 | /// 450 | public static void AddGloVar(string name, ScriptObject obj) 451 | { 452 | RunEnvironment.Instance.Global.AddFileld(name, obj); 453 | } 454 | 455 | /// 456 | /// 获取全局Nil只读字段 457 | /// 458 | /// 459 | public static ScriptObject GetNil() 460 | { 461 | return RunEnvironment.Nil; 462 | } 463 | 464 | /// 465 | /// 获取全局False只读字段 466 | /// 467 | /// 468 | public static ScriptObject GetFalse() 469 | { 470 | return RunEnvironment.False; 471 | } 472 | 473 | /// 474 | /// 获取全局True只读字段 475 | /// 476 | /// 477 | public static ScriptObject GetTrue() 478 | { 479 | return RunEnvironment.True; 480 | } 481 | 482 | 483 | 484 | 485 | #region 二元运算 486 | 487 | /// 488 | /// 加法 489 | /// 490 | public static ScriptObject Add(ScriptObject obj1,ScriptObject obj2) 491 | { 492 | if (obj1.Type != obj2.Type) 493 | { 494 | return GetNil(); 495 | } 496 | if (obj1.Type == ValueType.NUMBER) 497 | { 498 | ScriptObject s = ScriptObject.CreateNum(obj1.Value.Number + obj2.Value.Number); 499 | return s; 500 | } 501 | return GetNil(); 502 | } 503 | 504 | /// 505 | /// 减法 506 | /// 507 | public static ScriptObject Subtract(ScriptObject obj1, ScriptObject obj2) 508 | { 509 | if (obj1.Type != obj2.Type) 510 | { 511 | return GetNil(); 512 | } 513 | if (obj1.Type == ValueType.NUMBER) 514 | { 515 | ScriptObject s = ScriptObject.CreateNum(obj1.Value.Number - obj2.Value.Number); 516 | return s; 517 | } 518 | return GetNil(); 519 | } 520 | 521 | /// 522 | /// 乘法 523 | /// 524 | public static ScriptObject Multiply(ScriptObject obj1, ScriptObject obj2) 525 | { 526 | if (obj1.Type != obj2.Type) 527 | { 528 | return GetNil(); 529 | } 530 | if (obj1.Type == ValueType.NUMBER) 531 | { 532 | ScriptObject s = ScriptObject.CreateNum(obj1.Value.Number * obj2.Value.Number); 533 | return s; 534 | } 535 | return GetNil(); 536 | } 537 | 538 | /// 539 | /// 除法 540 | /// 541 | public static ScriptObject Divide(ScriptObject obj1, ScriptObject obj2) 542 | { 543 | if (obj1.Type != obj2.Type) 544 | { 545 | return GetNil(); 546 | } 547 | if (obj1.Type == ValueType.NUMBER) 548 | { 549 | ScriptObject s = ScriptObject.CreateNum(obj1.Value.Number / obj2.Value.Number); 550 | return s; 551 | } 552 | return GetNil(); 553 | } 554 | 555 | /// 556 | /// 比较是否相等 557 | /// 558 | public static ScriptObject Equal(ScriptObject obj1, ScriptObject obj2) 559 | { 560 | if(obj1.Type != obj2.Type) 561 | { 562 | return GetNil(); 563 | } 564 | if(obj1.Type == ValueType.NUMBER) 565 | { 566 | return obj1.Value.Number == obj2.Value.Number ? GetTrue() : GetFalse(); 567 | } 568 | if(obj1.Type == ValueType.BOOLEAN) 569 | { 570 | return obj1.Value.Boolean == obj2.Value.Boolean ? GetTrue() : GetFalse(); 571 | } 572 | if (obj1.Type == ValueType.STRING) 573 | { 574 | return obj1.Value.RefPartHandle.StringValue == obj2.Value.RefPartHandle.StringValue ? GetTrue() : GetFalse(); 575 | } 576 | return GetFalse(); 577 | } 578 | 579 | /// 580 | /// 比较是否不相等 581 | /// 582 | public static ScriptObject NotEqual(ScriptObject obj1, ScriptObject obj2) 583 | { 584 | if (obj1.Type != obj2.Type) 585 | { 586 | return GetNil(); 587 | } 588 | if (obj1.Type == ValueType.NUMBER) 589 | { 590 | return obj1.Value.Number != obj2.Value.Number ? GetTrue() : GetFalse(); 591 | } 592 | 593 | if (obj2.Type == ValueType.BOOLEAN) 594 | { 595 | return obj1.Value.Boolean != obj2.Value.Boolean ? GetTrue() : GetFalse(); 596 | } 597 | return GetFalse(); 598 | } 599 | 600 | /// 601 | /// 大于 602 | /// 603 | public static ScriptObject GreaterThan(ScriptObject obj1, ScriptObject obj2) 604 | { 605 | if (obj1.Type != obj2.Type) 606 | { 607 | return GetNil(); 608 | } 609 | if (obj1.Type == ValueType.NUMBER) 610 | { 611 | return obj1.Value.Number > obj2.Value.Number ? GetTrue() : GetFalse(); 612 | } 613 | return GetFalse(); 614 | } 615 | 616 | /// 617 | /// 大于等于 618 | /// 619 | public static ScriptObject GreaterThanOrEqual(ScriptObject obj1, ScriptObject obj2) 620 | { 621 | if (obj1.Type != obj2.Type) 622 | { 623 | return GetNil(); 624 | } 625 | if (obj1.Type == ValueType.NUMBER) 626 | { 627 | return obj1.Value.Number < obj2.Value.Number ? GetFalse() : GetTrue(); 628 | } 629 | return GetFalse(); 630 | } 631 | 632 | /// 633 | /// 小于 634 | /// 635 | public static ScriptObject LessThan(ScriptObject obj1, ScriptObject obj2) 636 | { 637 | if (obj1.Type != obj2.Type) 638 | { 639 | return GetNil(); 640 | } 641 | if (obj1.Type == ValueType.NUMBER) 642 | { 643 | return obj1.Value.Number < obj2.Value.Number ? GetTrue() : GetFalse(); 644 | } 645 | return GetFalse(); 646 | } 647 | 648 | /// 649 | /// 小于等于 650 | /// 651 | public static ScriptObject LessThanOrEqual(ScriptObject obj1, ScriptObject obj2) 652 | { 653 | if (obj1.Type != obj2.Type) 654 | { 655 | return GetNil(); 656 | } 657 | if (obj1.Type == ValueType.NUMBER) 658 | { 659 | return obj1.Value.Number > obj2.Value.Number ? GetFalse() : GetTrue(); 660 | } 661 | return GetFalse(); 662 | } 663 | #endregion 664 | 665 | 666 | 667 | public static void StackPop(int count) 668 | { 669 | StackState stack = RunEnvironment.Instance.LocalStack; 670 | stack.Pop(count); 671 | } 672 | 673 | 674 | /// 675 | /// 将局部变量压栈 676 | /// 677 | /// 678 | public static void StackPush(ScriptObject obj) 679 | { 680 | StackState stack = RunEnvironment.Instance.LocalStack; 681 | stack.Push(obj); 682 | } 683 | 684 | /// 685 | /// 函数压栈 686 | /// 687 | /// 688 | /// 返回栈中的位置下表 689 | public static void PushFunction(ScriptObject func) 690 | { 691 | StackState stack = RunEnvironment.Instance.LocalStack; 692 | stack.PushFunction(func); 693 | } 694 | /// 695 | /// 函数参数压栈 696 | /// 697 | /// 698 | public static void PushParameter(ScriptObject parameter) 699 | { 700 | StackState stack = RunEnvironment.Instance.LocalStack; 701 | stack.PushFuncParameter(parameter); 702 | } 703 | 704 | /// 705 | /// 调用栈中的函数 706 | /// 707 | public static ScriptObject InvokeFuncInStack() 708 | { 709 | StackState stack = RunEnvironment.Instance.LocalStack; 710 | 711 | return stack.InvokeFunction(); 712 | } 713 | 714 | /// 715 | /// 设置返回值为空 716 | /// 717 | public static void SetReturnVoid() 718 | { 719 | StackState stack = RunEnvironment.Instance.LocalStack; 720 | stack.SetReturnVoid(); 721 | } 722 | 723 | public static void SetReturn(ScriptObject res) 724 | { 725 | StackState stack = RunEnvironment.Instance.LocalStack; 726 | stack.SetReturn(res); 727 | } 728 | 729 | 730 | 731 | /// 732 | /// 将栈上某值清空为nil 733 | /// 734 | /// 735 | public static void ClearStackVarAt(int offset) 736 | { 737 | StackState stack = RunEnvironment.Instance.LocalStack; 738 | ScriptObject s = stack.GetStackVar(offset); 739 | AssignVar(s, RunEnvironment.Nil); //仅赋nil,退栈时清空 740 | } 741 | /// 742 | /// 将表中某字段清掉 743 | /// 744 | public static void ClearTableFileld(ScriptObject own,string name) 745 | { 746 | own.RemoveFileld(name); 747 | } 748 | 749 | public static void ClearTableItem(ScriptObject own, ScriptObject index) 750 | { 751 | own.RemoveFileld(index); 752 | } 753 | 754 | 755 | public static ScriptObject CreateTable() 756 | { 757 | return ScriptObject.CreateTable(); 758 | } 759 | 760 | public static ScriptObject TableAddFileld(ScriptObject table,string name,ScriptObject value) 761 | { 762 | table.AddFileld(name,value); 763 | return table; 764 | } 765 | 766 | public static ScriptObject TableAddInArray(ScriptObject table,ScriptObject value) 767 | { 768 | table.AddInArray(value); 769 | return table; 770 | } 771 | 772 | /// 773 | /// 设置Upvalues的长度 774 | /// 775 | public static void SetUpvaluesLength(ScriptObject function,int length) 776 | { 777 | Contract.Assert(function.Type == ValueType.FUNCTION); 778 | 779 | FuncPart func = function.Value.RefPartHandle.ConverToFuncPart(); 780 | 781 | func.UpVals = new ScriptObject[length]; 782 | 783 | } 784 | 785 | /// 786 | /// 设置每一个UpValue 787 | /// 788 | public static void SetUpvalue(ScriptObject function, int at, int stackIndex) 789 | { 790 | Contract.Assert(function.Type == ValueType.FUNCTION); 791 | 792 | FuncPart func = function.Value.RefPartHandle.ConverToFuncPart(); 793 | 794 | func.UpVals[at] = RunEnvironment.Instance.LocalStack.GetVarFromBase(stackIndex); 795 | } 796 | 797 | 798 | public static void SetThisValue(ScriptObject own) 799 | { 800 | StackState stack = RunEnvironment.Instance.LocalStack; 801 | Instructor.AssignVar(stack.This, own); 802 | } 803 | 804 | 805 | public static ScriptObject GetThisValue() 806 | { 807 | StackState stack = RunEnvironment.Instance.LocalStack; 808 | return stack.This; 809 | } 810 | } 811 | } 812 | -------------------------------------------------------------------------------- /src/RunTime/RefPartBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.Contracts; 5 | 6 | namespace ScriptInterpreter.RunTime 7 | { 8 | public abstract class RefPartBase 9 | { 10 | internal StringPart ConverToStringPart() 11 | { 12 | Contract.Assert(this is StringPart); 13 | return this as StringPart; 14 | } 15 | internal FuncPart ConverToFuncPart() 16 | { 17 | Contract.Assert(this is FuncPart); 18 | return this as FuncPart; 19 | } 20 | 21 | internal TablePart ConverToTablePart() 22 | { 23 | Contract.Assert(this is TablePart); 24 | return this as TablePart; 25 | } 26 | 27 | public string StringValue 28 | { 29 | get { return ConverToStringPart().Value; } 30 | } 31 | 32 | public static StringPart CreateStrPart(string value) 33 | { 34 | return new StringPart(value); 35 | } 36 | 37 | public static FuncPart CreateFuncPart(Action func, int argCount, bool isUncertainParameters) 38 | { 39 | return new FuncPart(func, argCount,isUncertainParameters); 40 | } 41 | 42 | internal static TablePart CreateTablePart() 43 | { 44 | return new TablePart(); 45 | } 46 | 47 | } 48 | 49 | public sealed class StringPart : RefPartBase 50 | { 51 | private string _value; 52 | 53 | public string Value 54 | { 55 | get { return _value; } 56 | set { _value = value; } 57 | } 58 | 59 | public StringPart(string value) 60 | { 61 | _value = value; 62 | } 63 | } 64 | 65 | public struct UntParAndCount 66 | { 67 | public Int32 Count; 68 | public bool IsUncertainParameters; 69 | } 70 | 71 | public sealed class FuncPart : RefPartBase 72 | { 73 | private Action _value; 74 | 75 | public Action Value 76 | { 77 | get { return _value; } 78 | set { _value = value; } 79 | } 80 | private Int32 _argsCount; 81 | 82 | public Int32 ArgsCount 83 | { 84 | get { return _argsCount; } 85 | set { _argsCount = value; } 86 | } 87 | 88 | private ScriptObject[] _upVals; 89 | 90 | public bool IsUncertainParameters; 91 | 92 | public ScriptObject[] UpVals 93 | { 94 | get { return _upVals; } 95 | 96 | set { _upVals = value; } 97 | } 98 | 99 | public FuncPart(Action func, Int32 argCount, bool isUncertainParameters) 100 | { 101 | _value = func; 102 | 103 | _argsCount = argCount; 104 | 105 | IsUncertainParameters = isUncertainParameters; 106 | } 107 | } 108 | 109 | public sealed class TablePart : RefPartBase 110 | { 111 | private Dictionary _value = new Dictionary(); 112 | 113 | //数组段的利用率以不低于 50% 为准 114 | private const int N_Size = 50; 115 | 116 | //默认数组段大小为0 117 | private ScriptObject[] _array = new ScriptObject[0]; 118 | 119 | public ScriptObject[] ArrayPart 120 | { 121 | get { return _array; } 122 | } 123 | 124 | public ScriptObject MetaTable { get; set; } 125 | 126 | 127 | //数组部分实际有效大小 128 | private int count; 129 | 130 | public int Count 131 | { 132 | get { return count; } 133 | } 134 | 135 | public TablePart() { } 136 | 137 | internal void Clear() 138 | { 139 | _value.Clear(); 140 | 141 | Array.Clear(_array, 0, _array.Length); 142 | } 143 | /// 144 | /// 先这样处理吧,没有找到算法的具体实现 145 | /// 146 | public void AddFileld(int index,ScriptObject value) 147 | { 148 | int newsize; 149 | 150 | if (index < 0) 151 | { 152 | AddFileld(index.ToString(), value); 153 | } 154 | else if (index < _array.Length) 155 | { 156 | _array[index] = value; 157 | ++count; 158 | } 159 | else if ((newsize = (count + 1) * 2) >= index) 160 | { 161 | Array.Resize(ref _array, newsize); 162 | _array[index] = value; 163 | ++count; 164 | } 165 | else 166 | { 167 | AddFileld(index.ToString(), value); 168 | } 169 | } 170 | 171 | public void AddFileld(string fileldName, ScriptObject scriptValue) 172 | { 173 | _value[fileldName] = scriptValue; 174 | } 175 | 176 | internal void AddInArray(ScriptObject obj) 177 | { 178 | AddFileld(count,obj); 179 | } 180 | internal bool Remove(string filed) 181 | { 182 | return _value.Remove(filed); 183 | } 184 | 185 | internal bool Remove(int index) 186 | { 187 | if (index < 0 || index >= _array.Length) 188 | 189 | return Remove(index.ToString()); 190 | 191 | _array[index] = null; 192 | return true; 193 | } 194 | 195 | /// 196 | /// 不存在就返回null 197 | /// 198 | /// 199 | /// 200 | public ScriptObject TryGetValue(string name) 201 | { 202 | ScriptObject resoult = null; 203 | 204 | if (_value.TryGetValue(name, out resoult) == true) 205 | { 206 | return resoult; 207 | } 208 | return resoult; 209 | } 210 | 211 | public ScriptObject IndexAt(int index) 212 | { 213 | if (index < 0 || index >= _array.Length) return TryGetValue(index.ToString()); 214 | 215 | return _array[index]; 216 | } 217 | 218 | 219 | 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/RunTime/RunEnvironment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.Contracts; 4 | using ScriptInterpreter.Lib; 5 | using System.Threading; 6 | using ScriptInterpreter.Parse; 7 | 8 | namespace ScriptInterpreter.RunTime 9 | { 10 | 11 | using SW = System.Windows; 12 | using System.Linq.Expressions; 13 | using ScriptInterpreter.Util; 14 | 15 | public class StackState 16 | { 17 | private List stack = new List(); 18 | 19 | private Stack _contextStartStack = new Stack(); 20 | 21 | private Stack _funcPushStack = new Stack(); 22 | 23 | /// 24 | /// 存放返回值 25 | /// 26 | private ScriptObject returnValue = ScriptObject.CreateNil(); 27 | 28 | /// 29 | /// 存放this引用 30 | /// 31 | private ScriptObject thisValue = ScriptObject.CreateNil(); 32 | 33 | public ScriptObject This 34 | { 35 | get { return thisValue; } 36 | set { thisValue = value; } 37 | } 38 | 39 | private int contextStart; 40 | 41 | public int Top 42 | { 43 | get { return stack.Count; } 44 | } 45 | 46 | internal StackState() 47 | { 48 | Inint(); 49 | } 50 | 51 | private void Inint() 52 | { 53 | contextStart = -1; 54 | } 55 | 56 | //从此开始进行栈上变量的查找 57 | public int VarStartPoint 58 | { 59 | get { return contextStart + 1; } 60 | } 61 | 62 | internal ScriptObject GetVarFromBase(int stackIndex) 63 | { 64 | return stack[stackIndex]; 65 | } 66 | 67 | internal ScriptObject GetStackVar(int offset) 68 | { 69 | Contract.Assert((contextStart + offset) <= stack.Count); 70 | return stack[offset + VarStartPoint]; 71 | } 72 | 73 | internal ScriptObject GetUpVar(int offset) 74 | { 75 | Contract.Assert(stack[contextStart].Type == ValueType.FUNCTION); 76 | 77 | return stack[contextStart].Value.RefPartHandle.ConverToFuncPart().UpVals[offset]; 78 | } 79 | 80 | 81 | 82 | /// 83 | /// 将函数压栈,准备调用 84 | /// 85 | /// 86 | internal void PushFunction(ScriptObject func) 87 | { 88 | Contract.Assert(func !=null && func.Type == ValueType.FUNCTION); 89 | 90 | stack.Add(func); 91 | 92 | _funcPushStack.Push(stack.Count - 1); //指向函数 93 | } 94 | /// 95 | /// 将函数参数压栈,准备调用函数 96 | /// 97 | /// 98 | internal void PushFuncParameter(ScriptObject parameter) 99 | { 100 | Contract.Assert(parameter!=null); 101 | 102 | int funcIndex = _funcPushStack.Peek(); 103 | 104 | FuncPart func = stack[funcIndex].Value.RefPartHandle.ConverToFuncPart(); 105 | 106 | //当前栈中的函数参数小于函数参数大小 107 | if (Top - (funcIndex + 1) < func.ArgsCount) 108 | { 109 | Push(parameter); 110 | } 111 | else if (func.IsUncertainParameters == true) //是不定参数 112 | { 113 | if (Top - (funcIndex + 1) == func.ArgsCount) 114 | { 115 | ScriptObject s = ScriptObject.CreateTable(); 116 | 117 | stack.Add(s); 118 | } 119 | ScriptObject args = stack[Top - 1]; 120 | args.AddInArray(parameter); 121 | } 122 | //否则,则省略掉传入参数 123 | } 124 | 125 | internal ScriptObject InvokeFunction() 126 | { 127 | return InvokeFuncAtIndex(_funcPushStack.Pop()); 128 | } 129 | 130 | /// 131 | /// 调用指定位置的函数 132 | /// 133 | private ScriptObject InvokeFuncAtIndex(int at) 134 | { 135 | Contract.Assert(stack[at].Type == ValueType.FUNCTION); 136 | 137 | FuncPart invokeFunc = stack[at].Value.RefPartHandle.ConverToFuncPart(); 138 | 139 | //如果函数的参数大于压入的参数,则不足部分补Nil 140 | while (invokeFunc.ArgsCount > Top - (at + 1)) 141 | { 142 | Push(RunEnvironment.Nil); 143 | } 144 | _contextStartStack.Push(contextStart); 145 | 146 | contextStart = at; //设置当前上下文,很重要 147 | 148 | invokeFunc.Value(); //委托调用 149 | 150 | stack.RemoveRange(at,Top - at); 151 | 152 | contextStart = _contextStartStack.Pop(); //恢复当前上下文 153 | 154 | Instructor.AssignVar(This,RunEnvironment.Nil); // this 指针清空 155 | 156 | return returnValue; 157 | } 158 | 159 | internal ScriptObject GetReturn() 160 | { 161 | return returnValue; 162 | } 163 | 164 | internal void SetReturn(ScriptObject scriptObject) 165 | { 166 | Contract.Assert(scriptObject!=null); 167 | 168 | Instructor.AssignVar(returnValue, scriptObject); 169 | } 170 | 171 | internal void SetReturnVoid() 172 | { 173 | SetReturn(RunEnvironment.Nil); 174 | } 175 | 176 | internal void CheckClear() 177 | { 178 | Contract.Assert(stack.Count == 0); 179 | Contract.Assert(contextStart == -1); 180 | } 181 | 182 | 183 | 184 | 185 | 186 | 187 | #region 堆栈操作函数 188 | 189 | internal int Push(ScriptObject obj) 190 | { 191 | ScriptObject o = ScriptObject.CreateScriptObject(obj); 192 | stack.Add(o); 193 | return Top - 1; 194 | } 195 | 196 | internal int Push(string str) 197 | { 198 | ScriptObject o = ScriptObject.CreateString(str); 199 | stack.Add(o); 200 | return Top - 1; 201 | } 202 | 203 | /// 204 | /// 弹出指定个数的元素 205 | /// 206 | /// 207 | internal void Pop(int count) 208 | { 209 | stack.RemoveRange(Top - count, count); 210 | } 211 | 212 | 213 | 214 | 215 | 216 | internal void InvokeFunction(ScriptObject function,params ScriptObject[] args) 217 | { 218 | this.PushFunction(function); 219 | 220 | foreach (ScriptObject i in args) 221 | { 222 | this.PushFuncParameter(i); 223 | } 224 | 225 | this.InvokeFunction(); 226 | } 227 | 228 | 229 | #endregion 230 | } 231 | 232 | 233 | public sealed class RunEnvironment 234 | { 235 | private static readonly Lazy _instance = new Lazy( () => new RunEnvironment()); 236 | 237 | private RunEnvironment() 238 | { 239 | InitializeComponent(); 240 | } 241 | 242 | public static RunEnvironment Instance 243 | { 244 | get { return _instance.Value ;} 245 | } 246 | 247 | private ScriptObject globalPool = ScriptObject.CreateTable(); 248 | 249 | private Parser parser = new Parser(new Scanner()); 250 | 251 | public Parser Parser 252 | { 253 | get { return parser; } 254 | } 255 | 256 | public ScriptObject Global 257 | { 258 | get { return globalPool; } 259 | } 260 | 261 | private StackState Stack = new StackState(); 262 | 263 | public StackState LocalStack 264 | { 265 | get { return Stack; } 266 | } 267 | 268 | /// 269 | /// 三个只读全局公共对象,只可用作右值表达式中 270 | /// 271 | public static readonly ScriptObject Nil = ScriptObject.CreateNil(); 272 | public static readonly ScriptObject False = ScriptObject.CreateBool(false); 273 | public static readonly ScriptObject True = ScriptObject.CreateBool(true); 274 | 275 | //载入一个函数 276 | internal bool LoadFunction(string name,Action fun,int argCount,bool isUncertainParameters = false) 277 | { 278 | ScriptObject s = ScriptObject.CreateFunction(fun, argCount, isUncertainParameters); 279 | Global.AddFileld(name, s); 280 | return true; 281 | } 282 | 283 | private void InitializeComponent() 284 | { 285 | Global.AddFileld("_G", Global); 286 | } 287 | 288 | public void Init() 289 | { 290 | Lightbrary.LoadLIB(); 291 | } 292 | 293 | public Expression CompilationUnit(string commandString) 294 | { 295 | if (string.IsNullOrWhiteSpace(commandString)) 296 | { 297 | return null; 298 | } 299 | 300 | Parser.S.InputString(commandString); 301 | 302 | Expression b = null; 303 | 304 | try 305 | { 306 | b = Parser.CompilationUnit(); 307 | 308 | Instructor.CompileIndexStack.CheckClear(); 309 | } 310 | catch (ScriptCompileException e) 311 | { 312 | Console.WriteLine(e.Message); 313 | Instructor.CompileIndexStack.Clear(); 314 | } 315 | return b; 316 | } 317 | 318 | public int Interprete(string commandString) 319 | { 320 | Expression b = CompilationUnit(commandString); 321 | 322 | if (b == null) return -1; 323 | 324 | Action a = Expression.Lambda(Parser.E.InvokeFunction(b, null)).Compile(); 325 | 326 | a(); 327 | 328 | RunEnvironment.Instance.LocalStack.CheckClear(); 329 | 330 | return 0; 331 | } 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /src/RunTime/ScriptObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Collections.Generic; 4 | using System.Diagnostics.Contracts; 5 | using System.Diagnostics; 6 | using System.Linq.Expressions; 7 | 8 | namespace ScriptInterpreter.RunTime 9 | { 10 | [StructLayout(LayoutKind.Explicit)] 11 | public struct ValueObject 12 | { 13 | 14 | [FieldOffset(0)] 15 | private double _number; 16 | 17 | public double Number 18 | { 19 | get { return _number; } 20 | set { _number = value; } 21 | } 22 | 23 | [FieldOffset(0)] 24 | private bool _boolean; 25 | 26 | public bool Boolean 27 | { 28 | get { return _boolean; } 29 | set { _boolean = value; } 30 | } 31 | 32 | [FieldOffset(8)] 33 | private RefPartBase _refHandle; 34 | 35 | public RefPartBase RefPartHandle 36 | { 37 | get { return _refHandle; } 38 | set { _refHandle = value; } 39 | } 40 | } 41 | 42 | public sealed class ValueType 43 | { 44 | private ValueType() { } 45 | 46 | public const int NIL = 0; // nil 47 | public const int BOOLEAN = NIL + 1; //boolean 48 | public const int NUMBER = BOOLEAN + 1; //number; 49 | public const int STRING = NUMBER + 1; //string 50 | public const int FUNCTION = STRING + 1; //function 51 | public const int TABLE = FUNCTION + 1; //table 52 | 53 | } 54 | public class ScriptObject 55 | { 56 | public ValueObject Value; 57 | 58 | private int _type; 59 | 60 | public int Type 61 | { 62 | get { return _type; } 63 | 64 | set 65 | { 66 | _type = value; 67 | } 68 | } 69 | 70 | private ScriptObject() { } 71 | 72 | public string GetString() 73 | { 74 | switch (Type) 75 | { 76 | case ValueType.NIL: 77 | return "nil"; 78 | 79 | case ValueType.BOOLEAN: 80 | return Value.Boolean.ToString(); 81 | 82 | case ValueType.NUMBER: 83 | return Value.Number.ToString(); 84 | 85 | case ValueType.STRING: 86 | return Value.RefPartHandle.ConverToStringPart().Value; 87 | 88 | case ValueType.FUNCTION: 89 | 90 | return "function"; 91 | 92 | case ValueType.TABLE: 93 | 94 | return "table"; 95 | 96 | default: 97 | Contract.Assert(false, "未定义"); 98 | return "未定义"; 99 | } 100 | } 101 | 102 | public override string ToString() 103 | { 104 | throw new NotImplementedException("ScriptObject的ToString()方法不用"); 105 | } 106 | 107 | public string GetTypeof() 108 | { 109 | switch (Type) 110 | { 111 | case ValueType.NIL: 112 | return "nil"; 113 | 114 | case ValueType.BOOLEAN: 115 | return "boolean"; 116 | 117 | case ValueType.NUMBER: 118 | return "number"; 119 | 120 | case ValueType.STRING: 121 | return "string"; 122 | 123 | case ValueType.FUNCTION: 124 | return "function"; 125 | 126 | case ValueType.TABLE: 127 | return "table"; 128 | 129 | default: 130 | Contract.Assert(false); 131 | return "未知"; 132 | } 133 | } 134 | 135 | /// 136 | /// 拷贝一个ScriptObject 137 | /// 138 | internal static ScriptObject CreateScriptObject(ScriptObject obj) 139 | { 140 | ScriptObject s = new ScriptObject(); 141 | Instructor.AssignVar(s, obj); 142 | return s; 143 | } 144 | 145 | /// 146 | /// 产生一个 nil 147 | /// 148 | /// 149 | public static ScriptObject CreateNil() 150 | { 151 | ScriptObject s = new ScriptObject(); 152 | s.Type = ValueType.NIL; 153 | return s; 154 | } 155 | /// 156 | /// 产生一个 num 157 | /// 158 | /// 159 | /// 160 | internal static ScriptObject CreateNum(double num) 161 | { 162 | ScriptObject s = new ScriptObject(); 163 | s.Type = ValueType.NUMBER; 164 | s.Value.Number = num; 165 | return s; 166 | } 167 | /// 168 | /// 产生一个bool 169 | /// 170 | /// 171 | /// 172 | internal static ScriptObject CreateBool(bool boolean) 173 | { 174 | ScriptObject s = new ScriptObject(); 175 | s.Type = ValueType.BOOLEAN; 176 | s.Value.Boolean = boolean; 177 | return s; 178 | } 179 | 180 | /// 181 | /// 产生一个表 182 | /// 183 | /// 184 | internal static ScriptObject CreateTable() 185 | { 186 | ScriptObject s = new ScriptObject(); 187 | s.Type = ValueType.TABLE; 188 | s.Value.RefPartHandle = RefPartBase.CreateTablePart(); 189 | return s; 190 | } 191 | 192 | /// 193 | /// 产生一个字符串 194 | /// 195 | /// 196 | /// 197 | internal static ScriptObject CreateString(string value) 198 | { 199 | ScriptObject s = new ScriptObject(); 200 | s.Type = ValueType.STRING; 201 | s.Value.RefPartHandle = RefPartBase.CreateStrPart(value); 202 | return s; 203 | } 204 | 205 | /// 206 | /// 产生一个函数 207 | /// 208 | /// 209 | /// 210 | internal static ScriptObject CreateFunction(Action func, int argCount, bool isUncertainParameters) 211 | { 212 | ScriptObject s = new ScriptObject(); 213 | s.Type = ValueType.FUNCTION; 214 | s.Value.RefPartHandle = RefPartBase.CreateFuncPart(func, argCount, isUncertainParameters); 215 | return s; 216 | } 217 | 218 | 219 | /// 220 | /// 添加字段 221 | /// 222 | /// 223 | /// 224 | internal void AddFileld(string name, ScriptObject obj) 225 | { 226 | Contract.Assert(Type == ValueType.TABLE); 227 | Value.RefPartHandle.ConverToTablePart().AddFileld(name, obj); 228 | } 229 | 230 | internal void AddFileld(int index, ScriptObject obj) 231 | { 232 | Contract.Assert(Type == ValueType.TABLE); 233 | Value.RefPartHandle.ConverToTablePart().AddFileld(index, obj); 234 | } 235 | 236 | internal void AddInArray(ScriptObject obj) 237 | { 238 | Contract.Assert(Type == ValueType.TABLE); 239 | Value.RefPartHandle.ConverToTablePart().AddInArray(obj); 240 | } 241 | 242 | /// 243 | /// 以名称获取字段,没有就返回nil 244 | /// 245 | /// 246 | /// 247 | public ScriptObject GetFileld(string filed) 248 | { 249 | Contract.Assert(Type == ValueType.TABLE); 250 | 251 | TablePart tablePart = Value.RefPartHandle.ConverToTablePart(); 252 | 253 | ScriptObject s = tablePart.TryGetValue(filed); 254 | 255 | if (s != null) return s; 256 | 257 | ScriptObject metaTable = tablePart.MetaTable; 258 | 259 | if (metaTable != null) 260 | { 261 | s = metaTable.GetFileld("_index"); 262 | 263 | if (s.Type == ValueType.TABLE) 264 | { 265 | return s.GetFileld(filed); 266 | } 267 | else if (s.Type == ValueType.FUNCTION) 268 | { 269 | //多一次拷贝(实际上) 270 | //RunEnvironment.Instance.LocalStack.InvokeFunction(s, this, ScriptObject.CreateString(filed)); 271 | 272 | StackState state = RunEnvironment.Instance.LocalStack; 273 | 274 | state.PushFunction(s); 275 | 276 | state.Push(this); 277 | 278 | state.Push(filed); 279 | 280 | return state.InvokeFunction(); 281 | } 282 | } 283 | return RunEnvironment.Nil; 284 | } 285 | 286 | internal ScriptObject GetFileld(ScriptObject index) 287 | { 288 | Contract.Assert(Type == ValueType.TABLE); 289 | 290 | ScriptObject s = null; 291 | 292 | switch (index.Type) 293 | { 294 | case ValueType.NUMBER: 295 | 296 | s = Value.RefPartHandle.ConverToTablePart().IndexAt((int)index.Value.Number); 297 | 298 | break; 299 | 300 | case ValueType.STRING: 301 | 302 | s = Value.RefPartHandle.ConverToTablePart().TryGetValue(index.Value.RefPartHandle.ConverToStringPart().Value); 303 | 304 | break; 305 | 306 | default: 307 | Contract.Assert(false); 308 | break; 309 | } 310 | if (s == null) return RunEnvironment.Nil; 311 | 312 | return s; 313 | } 314 | 315 | 316 | public void RemoveFileld(string filed) 317 | { 318 | Contract.Assert(Type == ValueType.TABLE); 319 | Value.RefPartHandle.ConverToTablePart().Remove(filed); 320 | } 321 | 322 | internal void RemoveFileld(ScriptObject index) 323 | { 324 | Contract.Assert(Type == ValueType.TABLE); 325 | 326 | switch (index.Type) 327 | { 328 | case ValueType.NUMBER: 329 | 330 | int at = (int)index.Value.Number; 331 | 332 | Value.RefPartHandle.ConverToTablePart().Remove(at); 333 | 334 | break; 335 | 336 | case ValueType.STRING: 337 | 338 | string key = index.Value.RefPartHandle.ConverToStringPart().Value; 339 | 340 | Value.RefPartHandle.ConverToTablePart().Remove(key); 341 | 342 | break; 343 | 344 | default: 345 | Contract.Assert(false); 346 | break; 347 | } 348 | } 349 | 350 | /// 351 | /// 获取字段,没有的话就产生一个nil 352 | /// 353 | /// 354 | /// 355 | public ScriptObject GetOrCreateFileld(string filed) 356 | { 357 | Contract.Assert(Type == ValueType.TABLE); 358 | 359 | TablePart table = Value.RefPartHandle.ConverToTablePart(); 360 | 361 | ScriptObject s = table.TryGetValue(filed); 362 | 363 | if (s == null) 364 | { 365 | s = ScriptObject.CreateNil(); 366 | table.AddFileld(filed, s); 367 | } 368 | return s; 369 | } 370 | 371 | internal ScriptObject GetOrCreateFileld(ScriptObject index) 372 | { 373 | Contract.Assert(Type == ValueType.TABLE); 374 | 375 | TablePart table = Value.RefPartHandle.ConverToTablePart(); 376 | 377 | ScriptObject s = null; 378 | 379 | switch (index.Type) 380 | { 381 | case ValueType.NUMBER: 382 | 383 | int at = (int)index.Value.Number; 384 | 385 | s = Value.RefPartHandle.ConverToTablePart().IndexAt(at); 386 | 387 | if (s == null) 388 | { 389 | s = ScriptObject.CreateNil(); 390 | } 391 | table.AddFileld(at, s); 392 | break; 393 | 394 | case ValueType.STRING: 395 | 396 | string key = index.Value.RefPartHandle.ConverToStringPart().Value; 397 | 398 | s = table.TryGetValue(key); 399 | if (s == null) 400 | { 401 | s = ScriptObject.CreateNil(); 402 | } 403 | table.AddFileld(key, s); 404 | 405 | break; 406 | 407 | default: 408 | Contract.Assert(false); 409 | break; 410 | } 411 | return s; 412 | } 413 | 414 | internal void ClearTable() 415 | { 416 | Contract.Assert(Type == ValueType.TABLE); 417 | 418 | TablePart table = Value.RefPartHandle.ConverToTablePart(); 419 | 420 | table.Clear(); 421 | } 422 | } 423 | } 424 | -------------------------------------------------------------------------------- /src/Util/ExpInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using ScriptInterpreter.Parse; 4 | using System.Diagnostics.Contracts; 5 | 6 | namespace ScriptInterpreter.Util 7 | { 8 | /// 9 | /// 表达式工具类吧 10 | /// 11 | public static class ExpInfo 12 | { 13 | public const int OrPrec = 4; 14 | 15 | //相等和不等的优先级数,例如 == ,!= 16 | public const int EqPrec = 9; 17 | 18 | //比较运算的优先级数 ,例如 >,<,>=,<=, 19 | public const int OrdPrec = 10; 20 | 21 | //加和减运算优先级, + ,- 22 | public const int AddPrec = 12; 23 | 24 | //乘除,取 mod 运算优先级数 , *,/,%(注意mod运算目前不支持,小数不能取mod) 25 | public const int MulPrec = 13; 26 | 27 | 28 | internal static int OpPrec(int token) 29 | { 30 | switch(token) 31 | { 32 | case Tokens.EQEQ: // == 33 | case Tokens.BANGEQ: // != 34 | return EqPrec; 35 | 36 | case Tokens.GT: // > 37 | case Tokens.GTEQ: // >= 38 | case Tokens.LT: // < 39 | case Tokens.LTEQ: // <= 40 | return OrdPrec; 41 | 42 | case Tokens.PLUS: // + 43 | case Tokens.SUB: // - 44 | return AddPrec; //加和减据返回12 优先级数 45 | 46 | case Tokens.STAR: // * 47 | case Tokens.SLASH: // / 48 | case Tokens.PERCENT: // % 49 | return MulPrec; 50 | 51 | default: 52 | return -1; //其他操作符,均设置为最低 53 | } 54 | 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Util/ExpMark.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using ScriptInterpreter.RunTime; 4 | using System.Collections.Generic; 5 | using ScriptInterpreter.Parse; 6 | using System.Diagnostics.Contracts; 7 | 8 | 9 | namespace ScriptInterpreter.Util 10 | { 11 | public class ExpMark : Tokens 12 | { 13 | private int pos; 14 | 15 | internal ExpMark At(int p) 16 | { 17 | pos = p; 18 | return this; 19 | } 20 | 21 | internal Expression CompilationUnit(TupleStruct info,List funcList, Expression body, LabelTarget label) 22 | { 23 | BlockExpression e = funcList.Count == 0 ? Expression.Block(body) : Expression.Block(Expression.Block(funcList), body); 24 | 25 | return MethodDef(info, e, label, null); 26 | } 27 | 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 要退栈的元素数 33 | /// 34 | internal BlockExpression Block(BlockExpression t, int count) 35 | { 36 | Contract.Assert(count>=0); 37 | 38 | if(count == 0) 39 | { 40 | return t; 41 | } 42 | return Expression.Block(t, Expression.Call(typeof(Instructor).GetMethod("StackPop"),count.GetConstantExpression())); 43 | } 44 | 45 | /// 46 | /// 局部变量定义 47 | /// 48 | /// 局部变量名 49 | /// 初始化的值 50 | /// 是外部变量,还是函数内变量 51 | /// 将当前变量压入栈的方法表达式 52 | internal Expression LocalVarDef(string localName, Expression init) 53 | { 54 | Instructor.CompileIndexStack.AddSymbolVar(localName); 55 | 56 | return Expression.Call(typeof(Instructor).GetMethod("StackPush"), init); 57 | } 58 | 59 | //数字常量 60 | internal Expression Number(string num) 61 | { 62 | return ScriptObject.CreateNum(double.Parse(num)).GetConstantExpression(); 63 | } 64 | 65 | internal Expression Assign(Expression t, Expression t1) 66 | { 67 | return Expression.Call(typeof(Instructor).GetMethod("AssignVar"), t, t1); 68 | } 69 | 70 | 71 | internal Expression Select(Expression t, string ident, bool isLvalue) 72 | { 73 | if (t == null) 74 | { 75 | return Instructor.GetVarByName(ident, isLvalue); 76 | } 77 | else 78 | { 79 | return Instructor.GetVarFromTable(t, ident, isLvalue); 80 | } 81 | } 82 | 83 | internal Expression Select(Expression t, Expression index, bool isLvalue) 84 | { 85 | Contract.Assert(t != null && index != null); 86 | 87 | return Instructor.GetVarFromTable(t, index, isLvalue); 88 | } 89 | 90 | /// 91 | /// 从t 中移除 ident 92 | /// 93 | /// 94 | /// 95 | /// 96 | internal Expression Remove(Expression t, string ident) 97 | { 98 | if (t == null) 99 | { 100 | return Instructor.RemoveVarByName(ident); 101 | } 102 | return Instructor.RemoveVarFromTable(t, ident); 103 | } 104 | 105 | internal Expression Remove(Expression t, Expression index) 106 | { 107 | Contract.Assert(t != null && index != null); 108 | 109 | return Instructor.RemoveVarFromTable(t, index); 110 | } 111 | 112 | 113 | internal Expression PosInc(Expression t, bool isFront) 114 | { 115 | if (isFront == true) 116 | { 117 | return Expression.Call(typeof(Instructor).GetMethod("IncPos"), t); 118 | } 119 | else 120 | { 121 | return Expression.Call(typeof(Instructor).GetMethod("PosInc"), t); 122 | } 123 | } 124 | internal Expression PosDec(Expression t, bool isFront) 125 | { 126 | if (isFront == true) 127 | { 128 | return Expression.Call(typeof(Instructor).GetMethod("DecPos"), t); 129 | } 130 | else 131 | { 132 | return Expression.Call(typeof(Instructor).GetMethod("PosDec"), t); 133 | } 134 | 135 | } 136 | 137 | /// 138 | /// 增加一个函数内的局部变量 139 | /// 140 | /// 141 | internal void DefMethodParameter(string localName) 142 | { 143 | Instructor.CompileIndexStack.AddSymbolVar(localName); 144 | } 145 | 146 | /// 147 | /// 定义一个全局函数 148 | /// 149 | internal Expression MethodDef(string name,Expression functionValue) 150 | { 151 | return Expression.Call(typeof(Instructor).GetMethod("AddGloVar"), name.GetConstantExpression(),functionValue); 152 | } 153 | 154 | /// 155 | /// 定义一个匿名函数 156 | /// 157 | /// 158 | /// TupleStruct 159 | /// @First 函数参数个数 160 | /// @Second 是否是不定参数 161 | /// 162 | /// 函数体 163 | /// 结束标记 164 | /// 闭包变量集合 165 | /// 166 | internal Expression MethodDef(TupleStruct info, BlockExpression body, LabelTarget label, List> upValues) 167 | { 168 | //函数体 169 | Expression funcBody = Expression.Block(body, Expression.Call(typeof(Instructor).GetMethod("SetReturnVoid")),Expression.Label(label)); 170 | 171 | Action func = Expression.Lambda(funcBody).Compile(); //编译方法体 172 | 173 | Expression o = ScriptObject.CreateFunction(func, info.First, info.Second).GetConstantExpression(); 174 | 175 | if (upValues == null || upValues.Count == 0) return o; 176 | 177 | List steps = new List(); 178 | 179 | Expression e = Expression.Call(typeof(Instructor).GetMethod("SetUpvaluesLength"), o, upValues.Count.GetConstantExpression()); 180 | 181 | steps.Add(e); 182 | 183 | for (int i = 0; i < upValues.Count; i++) 184 | { 185 | KeyValuePair upvalue = upValues[i]; 186 | 187 | e = Expression.Call(typeof(Instructor).GetMethod("SetUpvalue"), o, i.GetConstantExpression(), upvalue.Value.GetConstantExpression()); 188 | 189 | steps.Add(e); 190 | } 191 | 192 | steps.Add(o); 193 | 194 | return Expression.Block(steps); 195 | } 196 | 197 | /// 198 | /// IfThenElse 表达式 199 | /// 200 | internal Expression IfThenElse(Expression cond, Expression thenpart, Expression elsepart) 201 | { 202 | if (elsepart == null) 203 | { 204 | return Expression.IfThen(Instructor.GetCondition(cond),thenpart); 205 | } 206 | return Expression.IfThenElse(Instructor.GetCondition(cond),thenpart, elsepart); 207 | } 208 | 209 | 210 | 211 | /// 212 | /// while 循环表达式 213 | /// 214 | /// 215 | /// 216 | /// 217 | internal Expression WhileLoop(Expression cond, Expression body, LabelTarget label) 218 | { 219 | return Expression.Loop( 220 | Expression.IfThenElse( 221 | Instructor.GetCondition(cond), 222 | body, 223 | Expression.Break(label) 224 | ), 225 | label 226 | ); 227 | } 228 | 229 | /// 230 | /// do while 循环表达式 231 | /// 232 | /// 233 | /// 234 | /// 235 | /// 236 | internal Expression DoWhileLoop(Expression body, Expression cond, LabelTarget labelTarget) 237 | { 238 | return Expression.Block(body, WhileLoop(cond, body, labelTarget)); 239 | } 240 | 241 | 242 | /// 243 | /// for 循环表达式 244 | /// 245 | /// 246 | /// 247 | /// 248 | /// 249 | /// 250 | internal Expression ForLoop(Expression inits, Expression cond, Expression steps, Expression body, LabelTarget labelTarget) 251 | { 252 | return Expression.Block(inits, WhileLoop(cond, Expression.Block(body, steps), labelTarget)); 253 | } 254 | 255 | /// 256 | /// break 表达式 257 | /// 258 | /// 259 | /// 260 | internal Expression Break(LabelTarget label) 261 | { 262 | return Expression.Break(label); 263 | } 264 | 265 | 266 | /// 267 | /// return 语句 268 | /// 269 | /// 270 | /// 271 | /// 272 | internal Expression Return(LabelTarget returnTarget, Expression result) 273 | { 274 | Expression t = result == null ? Expression.Call(typeof(Instructor).GetMethod("SetReturnVoid")) : Expression.Call(typeof(Instructor).GetMethod("SetReturn"), result); 275 | return Expression.Block(t, Expression.Return(returnTarget)); 276 | } 277 | 278 | internal Expression InvokeFunction(Expression own, Expression t, List args) 279 | { 280 | Expression t0 = Expression.Call(typeof(Instructor).GetMethod("PushFunction"), t); 281 | 282 | Expression t1 = Expression.Call(typeof(Instructor).GetMethod("SetThisValue"), own); 283 | 284 | Expression t2 = Expression.Call(typeof(Instructor).GetMethod("InvokeFuncInStack")); 285 | 286 | if (args == null || args.Count == 0) 287 | { 288 | return Expression.Block(t0,t1,t2); 289 | } 290 | 291 | List stepBlock = new List(); 292 | 293 | stepBlock.Add(t0); //记录下函数压栈的下表 294 | 295 | foreach (var i in args) 296 | { 297 | stepBlock.Add(Expression.Call(typeof(Instructor).GetMethod("PushParameter"), i)); //参数入栈 298 | } 299 | stepBlock.Add(t1); //设置this指针 300 | 301 | stepBlock.Add(t2); //函数调用 302 | 303 | return Expression.Block(stepBlock); 304 | } 305 | 306 | 307 | /// 308 | /// 调用函数t,args为参数 309 | /// 310 | /// 311 | /// 312 | /// 313 | internal Expression InvokeFunction(Expression t, List args) 314 | { 315 | Expression t1 = Expression.Call(typeof(Instructor).GetMethod("PushFunction"), t); 316 | 317 | Expression t2 = Expression.Call(typeof(Instructor).GetMethod("InvokeFuncInStack")); 318 | 319 | if (args == null || args.Count == 0) 320 | { 321 | return Expression.Block(t1,t2); 322 | } 323 | 324 | List stepBlock = new List(); 325 | 326 | stepBlock.Add(t1); //记录下函数压栈的下表 327 | 328 | foreach (var i in args) 329 | { 330 | stepBlock.Add(Expression.Call(typeof(Instructor).GetMethod("PushParameter"), i)); //参数入栈 331 | } 332 | stepBlock.Add(t2); //函数调用 333 | 334 | return Expression.Block(stepBlock); 335 | } 336 | 337 | //字符串连接符 338 | internal Expression LinkStr(Expression t, Expression t1) 339 | { 340 | return Expression.Call(typeof(Instructor).GetMethod("LinkStr"), t, t1); 341 | } 342 | /// 343 | /// 加法 344 | /// 345 | private Expression Add(Expression t1, Expression t2) 346 | { 347 | return Expression.Add(t1, t2, typeof(Instructor).GetMethod("Add")); 348 | } 349 | /// 350 | /// 减法 351 | /// 352 | private Expression Subtract(Expression t1, Expression t2) 353 | { 354 | return Expression.Subtract(t1, t2, typeof(Instructor).GetMethod("Subtract")); 355 | } 356 | /// 357 | /// 乘法 358 | /// 359 | private Expression Multiply(Expression t1, Expression t2) 360 | { 361 | return Expression.Multiply(t1, t2, typeof(Instructor).GetMethod("Multiply")); 362 | } 363 | 364 | 365 | /// 366 | /// 除法 367 | /// 368 | private Expression Divide(Expression t1, Expression t2) 369 | { 370 | return Expression.Divide(t1, t2, typeof(Instructor).GetMethod("Divide")); 371 | } 372 | 373 | 374 | 375 | /// 376 | /// 判断是否相等 377 | /// 378 | /// 返回的是bool类型 379 | internal Expression Equal(Expression t, Expression t1) 380 | { 381 | return Expression.Equal(t, t1, false, typeof(Instructor).GetMethod("Equal")); 382 | } 383 | 384 | /// 385 | /// 判断是否不相等 386 | /// 387 | /// 返回的是bool类型 388 | internal Expression NotEqual(Expression t, Expression t1) 389 | { 390 | return Expression.Equal(t, t1, false, typeof(Instructor).GetMethod("NotEqual")); 391 | } 392 | 393 | 394 | /// 395 | /// 判断大于 396 | /// 397 | /// 398 | internal Expression GreaterThan(Expression t, Expression t1) 399 | { 400 | return Expression.GreaterThan(t, t1, false, typeof(Instructor).GetMethod("GreaterThan")); ; 401 | } 402 | 403 | 404 | /// 405 | /// 判断大于等于 406 | /// 407 | /// 返回的是bool类型 408 | internal Expression GreaterThanOrEqual(Expression t, Expression t1) 409 | { 410 | return Expression.GreaterThanOrEqual(t, t1, false, typeof(Instructor).GetMethod("GreaterThanOrEqual")); 411 | } 412 | 413 | /// 414 | /// 判断小于 415 | /// 416 | /// 返回的是bool类型 417 | internal Expression LessThan(Expression t, Expression t1) 418 | { 419 | return Expression.LessThan(t, t1, false, typeof(Instructor).GetMethod("LessThan")); 420 | } 421 | 422 | /// 423 | /// 判断小于等于 424 | /// 425 | /// 返回的是bool类型 426 | internal Expression LessThanOrEqual(Expression t, Expression t1) 427 | { 428 | return Expression.LessThanOrEqual(t, t1, false, typeof(Instructor).GetMethod("LessThanOrEqual")); 429 | } 430 | 431 | /// 432 | /// 根据表达式处理二元运算 433 | /// 434 | /// 435 | /// 436 | /// 437 | /// 438 | internal Expression MakeOp(int topOp, Expression t1, Expression t2) 439 | { 440 | switch (topOp) 441 | { 442 | case EQEQ: // == 443 | return Equal(t1, t2); 444 | 445 | case BANGEQ: // != 446 | return NotEqual(t1, t2); 447 | 448 | case GT: // > 449 | return GreaterThan(t1, t2); 450 | 451 | case GTEQ: // >= 452 | return GreaterThanOrEqual(t1, t2); 453 | 454 | case LT: // < 455 | return LessThan(t1, t2); 456 | 457 | case LTEQ: // <= 458 | return LessThanOrEqual(t1, t2); 459 | 460 | case PLUS: // + 461 | return Add(t1, t2); 462 | 463 | case SUB: // - 464 | return Subtract(t1, t2); 465 | 466 | case STAR: 467 | return Multiply(t1, t2); 468 | 469 | case SLASH: 470 | return Divide(t1, t2); 471 | 472 | 473 | } 474 | throw new NotImplementedException(); 475 | } 476 | /// 477 | /// 产生常量字符串 478 | /// 479 | /// 480 | /// 481 | internal Expression String(string str) 482 | { 483 | return ScriptObject.CreateString(str).GetConstantExpression(); 484 | } 485 | /// 486 | /// 返回False 487 | /// 488 | /// 489 | internal Expression Flase() 490 | { 491 | return Instructor.GetFalse().GetConstantExpression(); 492 | } 493 | /// 494 | /// 返回True 495 | /// 496 | /// 497 | internal Expression True() 498 | { 499 | return Instructor.GetTrue().GetConstantExpression(); 500 | } 501 | /// 502 | /// 返回table 503 | /// 504 | internal Expression Table(Expression t, List> elems) 505 | { 506 | if (t == null) 507 | { 508 | t = Expression.Call(typeof(Instructor).GetMethod("CreateTable")); 509 | } 510 | foreach (var i in elems) 511 | { 512 | if(i.Key == null) 513 | { 514 | t = Expression.Call(typeof(Instructor).GetMethod("TableAddInArray"), t, i.Value); 515 | } 516 | else 517 | { 518 | t = Expression.Call(typeof(Instructor).GetMethod("TableAddFileld"), t, i.Key.GetConstantExpression(), i.Value); 519 | } 520 | } 521 | return t; 522 | } 523 | 524 | 525 | /// 526 | /// 三目运算 527 | /// 528 | internal Expression Conditional(Expression t, Expression t1, Expression t2) 529 | { 530 | return Expression.Condition(Instructor.GetCondition(t), t1, t2); 531 | } 532 | 533 | /// 534 | /// 获取this指针 535 | /// 536 | internal Expression GetThisValue() 537 | { 538 | return Expression.Call(typeof(Instructor).GetMethod("GetThisValue")); 539 | } 540 | 541 | } 542 | } 543 | -------------------------------------------------------------------------------- /src/Util/ScriptUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScriptInterpreter.Parse; 3 | 4 | namespace ScriptInterpreter.Util 5 | { 6 | public struct TupleStruct 7 | { 8 | public T0 First; 9 | public T1 Second; 10 | 11 | public TupleStruct(T0 t0,T1 t1) 12 | { 13 | First = t0; 14 | Second = t1; 15 | } 16 | } 17 | 18 | public class ScriptCompileException : Exception 19 | { 20 | private ScriptCompileException(string message) 21 | : base(message) 22 | { 23 | } 24 | 25 | public static ScriptCompileException CreateContentExist(string symbol) 26 | { 27 | return new ScriptCompileException(string.Format("上下文已存在符号 {0} ", symbol)); 28 | } 29 | 30 | public static ScriptCompileException CreateIsNotIdentifier(string symbol) 31 | { 32 | return new ScriptCompileException(string.Format("符号 {0} 不是标识符", symbol)); 33 | } 34 | 35 | public static ScriptCompileException CreateSyntaxError(int line,int col,int token,string symbol) 36 | { 37 | switch (token) 38 | { 39 | case Tokens.PLUS: 40 | symbol = "+"; 41 | break; 42 | 43 | case Tokens.SUB: 44 | symbol = "-"; 45 | break; 46 | default: 47 | break; 48 | } 49 | return new ScriptCompileException(string.Format("{0}行{1}列->符号{2}附近存在语法错误", line, col,symbol)); 50 | } 51 | } 52 | 53 | 54 | public class ScriptRunTimeException : Exception 55 | { 56 | 57 | public ScriptRunTimeException(string message) 58 | : base(message) 59 | { 60 | 61 | } 62 | 63 | 64 | 65 | } 66 | } 67 | --------------------------------------------------------------------------------