[C#] 使用 C# 重新製作一個語言 - Hello World
2012-10-05
繼續上一篇文章http://www.dotblogs.com.tw/junegoat/archive/2012/09/16/c-sharp-make-a-language-lia-start.aspx
我們如何來進行編譯 sample.lia 的文檔呢?!
因為目前只有print 還有 printline 得部分..
對於 ILGenerator.Emit Method 還不致於太難..
首先我們得先驗證文法 是不是符合我定義的Lia 規範:
/// <summary> /// 驗證是否符合DTD規範的XML文件 /// </summary> /// <param name="xmlPath"> 該xml 文檔位置</param> /// <returns></returns> public static bool IsValidXML(string xmlPath) { var xmlReaderSettings = new XmlReaderSettings(); //如果設定為Igonre就會不驗證DTD 指驗證XML 的完整性 // xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore; xmlReaderSettings.DtdProcessing = DtdProcessing.Parse; //設定為DTD psrse xmlReaderSettings.ValidationType = ValidationType.DTD; xmlReaderSettings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; XmlReader reader = XmlReader.Create(xmlPath, xmlReaderSettings); try { while (reader.Read()) { } } catch (Exception ex) { Console.WriteLine("\r\n" + "----------- Lia Compiler Result -----------" + "\r\n"); Console.WriteLine("Error! This is not valid Lia gramma >" + ex.Message + "\r\n"); return false; } finally { //記得關閉免得被lock reader.Close(); } return true; }
透過這方式,就可以很簡單去判斷如對方輸入奇怪的字眼並非是我預期的..
譬如,我在Lia sample code 裡面鍵入echo 他並沒有符合我的規範..
再來 就是 關於 主程式部分
static void Main(string[] args) { //驗證 確保輸入 code source 還有輸出路徑 if (args.Length != 2) { Console.WriteLine("\r\n使用方式: Liac.exe source.xml target.exe"); return; } try { //判斷source 檔案是否真的存在 if (!File.Exists(AppDomain.CurrentDomain.BaseDirectory + args[0])) { Console.WriteLine("\r\n" + "----------- Lia Compiler Result -----------" + "\r\n"); Console.WriteLine("Error! I can't find the source >" + args[0] + "\r\n"); return; } //判斷文法 是否符合 Lia 規範 var isValid = IsValidXML(AppDomain.CurrentDomain.BaseDirectory + args[0]); if (!isValid) { return; } Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory + args[0]); CodeGenerator codeGenerator = new CodeGenerator(); // 因為只是先測試 print printline 所以都先封裝在一個function 內部測試 codeGenerator.TestPrintPrintline(args[1], File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + args[0])); Console.WriteLine("\r\n" + "----------- Lia Compiler Result -----------" + "\r\n"); Console.WriteLine("Success! Output File > " + args[1] + "\r\n"); } catch (Exception ex) { Console.Error.WriteLine(ex.Message); } }
上述程式很簡單,只是驗證 還有處理一些 compile 時候錯誤或是成功訊息提式..
真正的處理部分我都先放在 CodeGenerator 部分, 因為只是先測試 所以我都先封裝在 TestPrintPrintline 這 function 中,這樣方便閱讀..
using System; using System.Reflection; using System.Reflection.Emit; using System.Xml; namespace LiaCompiler { public class CodeGenerator { public void TestPrintPrintline(string outFileName, string xmlSource) { AssemblyName am = new AssemblyName(); am.Name = outFileName.ToUpper().Replace(".LIA", ""); AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(am, AssemblyBuilderAccess.Save); //訂立一永續性模組 ModuleBuilder mb = ab.DefineDynamicModule(am.Name, outFileName); TypeBuilder tb = mb.DefineType("LiaType", TypeAttributes.Public); MethodBuilder metb = tb.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, null, null); ab.SetEntryPoint(metb); ILGenerator il = metb.GetILGenerator(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(xmlSource);
foreach (XmlNode node in xmlDocument.ChildNodes) { //讀取Lia Element 中資料 if (node.Name == "Lia") { foreach (XmlNode liaNode in node.ChildNodes) { //建議這樣拆 處理每一個特殊的element if (liaNode.Name == "print") { AddPrintSegment(il, liaNode); } else if (liaNode.Name == "printline") { AddPrintlineSegment(il, liaNode); } } } } //返回計算 il.Emit(OpCodes.Ret); tb.CreateType(); ab.Save(outFileName); } private void AddPrintSegment(ILGenerator ilGenerator, XmlNode node) { //插入變量後 執行write 印出 ilGenerator.Emit(OpCodes.Ldstr, node.InnerText); ilGenerator.Emit(OpCodes.Call, typeof(System.Console).GetMethod("Write", new System.Type[] { typeof(string) })); } private void AddPrintlineSegment(ILGenerator ilGenerator, XmlNode node) { //插入 執行writeline ilGenerator.EmitWriteLine(node.InnerText); } } }
這樣我們就可以編譯 sample.lia 檔案..
查看一次MSIL Code
執行結果 compile and run
基本上 簡單的你就製作一個具有 print 還有 printline 的語言..
當然在公司 Lia Language Project 依然緩慢進行中..不過玩到後面你會覺得越來越困難,當然也會越來越好玩.
範例下載:
參考文件:
http://msdn.microsoft.com/en-us/library/system.reflection.emit.ilgenerator.emit.aspx
http://msdn.microsoft.com/en-us/library/aa329957(v=vs.71).aspx
http://msdn.microsoft.com/en-us/magazine/cc136756.aspx