/SimpleCC/SimpleCCompiler/Emitter.cs

https://github.com/nicroto/SimpleCC · C# · 276 lines · 258 code · 16 blank · 2 comment · 38 complexity · a32226d46df4095fa2563ef26c97d6da MD5 · raw file

  1. using System.Reflection;
  2. using System.IO;
  3. using System.Reflection.Emit;
  4. using System.Collections.Generic;
  5. using System;
  6. namespace SimpleC
  7. {
  8. class Emitter
  9. {
  10. ILGenerator il = null;
  11. Dictionary<string, LocalBuilder> symbolTable;
  12. public Emitter(List<Statement> statements, string moduleName)
  13. {
  14. if (Path.GetFileName(moduleName) != moduleName)
  15. {
  16. throw new System.Exception("can only output into current directory!");
  17. }
  18. AssemblyName name = new AssemblyName(Path.GetFileNameWithoutExtension(moduleName));
  19. AssemblyBuilder asmb = System.AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save);
  20. ModuleBuilder modb = asmb.DefineDynamicModule(moduleName);
  21. TypeBuilder typeBuilder = modb.DefineType("Foo");
  22. MethodBuilder methb = typeBuilder.DefineMethod("Main", MethodAttributes.Static, typeof(void), System.Type.EmptyTypes);
  23. // CodeGenerator
  24. this.il = methb.GetILGenerator();
  25. this.symbolTable = new Dictionary<string, LocalBuilder>();
  26. // Go Compile!
  27. foreach(var statement in statements)
  28. this.GenerateStatement(statement);
  29. this.il.Emit(OpCodes.Ldstr, "The Program has finished execution. Press any key to exit.");
  30. this.il.Emit(OpCodes.Call, typeof(Console).GetMethod(
  31. "WriteLine",
  32. new Type[] { typeof(string) }
  33. ));
  34. this.il.Emit(OpCodes.Call, typeof(System.Console).GetMethod(
  35. "ReadKey",
  36. BindingFlags.Public | BindingFlags.Static,
  37. null,
  38. new System.Type[] { },
  39. null
  40. ));
  41. il.Emit(OpCodes.Ret);
  42. typeBuilder.CreateType();
  43. modb.CreateGlobalFunctions();
  44. asmb.SetEntryPoint(methb);
  45. asmb.Save(moduleName);
  46. this.symbolTable = null;
  47. this.il = null;
  48. }
  49. private void GenerateStatement(Statement statement)
  50. {
  51. GenerateExpression(statement.Expression);
  52. }
  53. private void GenerateExpression(Expression expression)
  54. {
  55. var bitwiseExpressions = expression.Operands;
  56. if (bitwiseExpressions.Count > 0)
  57. {
  58. GenerateBitwiseExpression(bitwiseExpressions[0]);
  59. if (bitwiseExpressions.Count > 1)
  60. for (var i = 1; i < bitwiseExpressions.Count; i++)
  61. {
  62. GenerateBitwiseExpression(bitwiseExpressions[i]);
  63. GenerateOperation(Operation.Or);
  64. }
  65. }
  66. }
  67. private void GenerateBitwiseExpression(BitwiseExpression bitwiseExpression)
  68. {
  69. var additiveExpressions = bitwiseExpression.Operands;
  70. if (additiveExpressions.Count > 0)
  71. {
  72. GenerateAdditiveExpression(additiveExpressions[0]);
  73. if (additiveExpressions.Count > 1)
  74. for (var i = 1; i < additiveExpressions.Count; i++)
  75. {
  76. GenerateAdditiveExpression(additiveExpressions[i]);
  77. GenerateOperation(Operation.And);
  78. }
  79. }
  80. }
  81. private void GenerateAdditiveExpression(AdditiveExpression additiveExpression)
  82. {
  83. var multiplicativeExpressions = additiveExpression.Operands;
  84. var operations = additiveExpression.Operations;
  85. if (multiplicativeExpressions.Count > 0)
  86. {
  87. GenerateMultiplicativeExpression(multiplicativeExpressions[0]);
  88. if (multiplicativeExpressions.Count > 1)
  89. for (var i = 1; i < multiplicativeExpressions.Count; i++)
  90. {
  91. GenerateMultiplicativeExpression(multiplicativeExpressions[i]);
  92. GenerateOperation(operations[i-1]);
  93. }
  94. }
  95. }
  96. private void GenerateMultiplicativeExpression(MultiplicativeExpression multiplicativeExpression)
  97. {
  98. var primaryExpressions = multiplicativeExpression.Operands;
  99. var operations = multiplicativeExpression.Operations;
  100. if (primaryExpressions.Count > 0)
  101. {
  102. GeneratePrimaryExpression(primaryExpressions[0]);
  103. if (primaryExpressions.Count > 1)
  104. for (var i = 1; i < primaryExpressions.Count; i++)
  105. {
  106. GeneratePrimaryExpression(primaryExpressions[i]);
  107. GenerateOperation(operations[i - 1]);
  108. }
  109. }
  110. }
  111. private void GeneratePrimaryExpression(PrimaryExpression primaryExpression)
  112. {
  113. if (primaryExpression is VariableIdent)
  114. {
  115. var variableIdent = primaryExpression as VariableIdent;
  116. var variableBuilder = this.symbolTable[variableIdent.Name];
  117. il.Emit(OpCodes.Ldloc, variableBuilder);
  118. }
  119. else if (primaryExpression is VariableAssignment)
  120. {
  121. var variableAssignment = primaryExpression as VariableAssignment;
  122. var name = variableAssignment.Name;
  123. if (!this.symbolTable.ContainsKey(name))
  124. this.symbolTable[name] = this.il.DeclareLocal(typeof(int));
  125. GenerateExpression(variableAssignment.Expression);
  126. il.Emit(OpCodes.Stloc, this.symbolTable[name]);
  127. }
  128. else if (primaryExpression is VariablePostIncrement)
  129. {
  130. var postIncrement = primaryExpression as VariablePostIncrement;
  131. var variableBuilder = this.symbolTable[postIncrement.Name];
  132. il.Emit(OpCodes.Ldloc, variableBuilder);
  133. GenerateIncrementOrDecrement(variableBuilder, InDeCrementStatus.PostIncrement);
  134. }
  135. else if (primaryExpression is VariablePostDecrement)
  136. {
  137. var postDecrement = primaryExpression as VariablePostDecrement;
  138. var variableBuilder = this.symbolTable[postDecrement.Name];
  139. il.Emit(OpCodes.Ldloc, variableBuilder);
  140. GenerateIncrementOrDecrement(variableBuilder, InDeCrementStatus.PostDecrement);
  141. }
  142. else if (primaryExpression is VariablePreIncrement)
  143. {
  144. var preIncrement = primaryExpression as VariablePreIncrement;
  145. var variableBuilder = this.symbolTable[preIncrement.Name];
  146. il.Emit(OpCodes.Ldloc, variableBuilder);
  147. GenerateIncrementOrDecrement(variableBuilder, InDeCrementStatus.PreIncrement);
  148. }
  149. else if (primaryExpression is VariablePreDecrement)
  150. {
  151. var preDecrement = primaryExpression as VariablePreDecrement;
  152. var variableBuilder = this.symbolTable[preDecrement.Name];
  153. il.Emit(OpCodes.Ldloc, variableBuilder);
  154. GenerateIncrementOrDecrement(variableBuilder, InDeCrementStatus.PreDecrement);
  155. }
  156. else if (primaryExpression is LogicalNotExpression)
  157. {
  158. var logicalNotExpression = primaryExpression as LogicalNotExpression;
  159. GeneratePrimaryExpression(logicalNotExpression.PrimaryExpression);
  160. GenerateOperation(Operation.Not);
  161. }
  162. else if (primaryExpression is Number)
  163. {
  164. var number = primaryExpression as Number;
  165. il.Emit(OpCodes.Ldc_I4, number.Value);
  166. }
  167. else if (primaryExpression is PrintFunction)
  168. {
  169. var printFunction = primaryExpression as PrintFunction;
  170. GenerateExpression(printFunction.Expression);
  171. this.il.Emit(OpCodes.Call, typeof(Console).GetMethod(
  172. "WriteLine",
  173. new Type[] { typeof(int) }
  174. ));
  175. }
  176. else if (primaryExpression is ScanFunction)
  177. {
  178. this.il.Emit(OpCodes.Call, typeof(System.Console).GetMethod(
  179. "ReadLine",
  180. BindingFlags.Public | BindingFlags.Static,
  181. null,
  182. new System.Type[] { },
  183. null
  184. ));
  185. this.il.Emit(OpCodes.Call, typeof(int).GetMethod(
  186. "Parse",
  187. BindingFlags.Public | BindingFlags.Static,
  188. null,
  189. new Type[] { typeof(string) },
  190. null
  191. ));
  192. }
  193. else if (primaryExpression is ParenthesesExpression)
  194. {
  195. var parenthesesExpression = primaryExpression as ParenthesesExpression;
  196. GenerateExpression(parenthesesExpression.Expression);
  197. }
  198. }
  199. private void GenerateOperation(Operation operation)
  200. {
  201. switch (operation)
  202. {
  203. case Operation.Multiplication:
  204. il.Emit(OpCodes.Mul);
  205. break;
  206. case Operation.Division:
  207. il.Emit(OpCodes.Div);
  208. break;
  209. case Operation.Percentage:
  210. il.Emit(OpCodes.Rem);
  211. break;
  212. case Operation.Summation:
  213. il.Emit(OpCodes.Add);
  214. break;
  215. case Operation.Subtraction:
  216. il.Emit(OpCodes.Sub);
  217. break;
  218. case Operation.Or:
  219. il.Emit(OpCodes.Or);
  220. break;
  221. case Operation.And:
  222. il.Emit(OpCodes.And);
  223. break;
  224. case Operation.Not:
  225. il.Emit(OpCodes.Not);
  226. break;
  227. }
  228. }
  229. private void GenerateIncrementOrDecrement(LocalBuilder variableBuilder, InDeCrementStatus status)
  230. {
  231. switch (status)
  232. {
  233. case InDeCrementStatus.PostIncrement:
  234. il.Emit(OpCodes.Dup);
  235. il.Emit(OpCodes.Ldc_I4_1);
  236. il.Emit(OpCodes.Add);
  237. il.Emit(OpCodes.Stloc, variableBuilder);
  238. break;
  239. case InDeCrementStatus.PostDecrement:
  240. il.Emit(OpCodes.Dup);
  241. il.Emit(OpCodes.Ldc_I4_1);
  242. il.Emit(OpCodes.Sub);
  243. il.Emit(OpCodes.Stloc, variableBuilder);
  244. break;
  245. case InDeCrementStatus.PreIncrement:
  246. il.Emit(OpCodes.Ldc_I4_1);
  247. il.Emit(OpCodes.Add);
  248. il.Emit(OpCodes.Dup);
  249. il.Emit(OpCodes.Stloc, variableBuilder);
  250. break;
  251. case InDeCrementStatus.PreDecrement:
  252. il.Emit(OpCodes.Ldc_I4_1);
  253. il.Emit(OpCodes.Sub);
  254. il.Emit(OpCodes.Dup);
  255. il.Emit(OpCodes.Stloc, variableBuilder);
  256. break;
  257. }
  258. }
  259. }
  260. }