Interpreter.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using NTERA.Core;
  6. namespace NTERA.Interpreter
  7. {
  8. public partial class Interpreter
  9. {
  10. private Lexer lex;
  11. private Token prevToken;
  12. private Token lastToken;
  13. private Dictionary<string, Value> vars;
  14. private Dictionary<string, Marker> loops;
  15. public delegate Value BasicFunction(List<Value> args);
  16. private readonly IConsole console;
  17. private int ifcounter;
  18. private Marker lineMarker;
  19. private bool exit;
  20. public Interpreter(IConsole console, string input)
  21. {
  22. this.console = console;
  23. lex = new Lexer(input);
  24. vars = new Dictionary<string, Value>();
  25. loops = new Dictionary<string, Marker>();
  26. ifcounter = 0;
  27. GenerateKeywordDictionary();
  28. GenerateFunctionDictionary();
  29. }
  30. public Value GetVar(string name)
  31. {
  32. if (!vars.ContainsKey(name))
  33. throw new Exception("Variable with name " + name + " does not exist.");
  34. return vars[name];
  35. }
  36. public void SetVar(string name, Value val)
  37. {
  38. if (!vars.ContainsKey(name)) vars.Add(name, val);
  39. else vars[name] = val;
  40. }
  41. void Error(string text)
  42. {
  43. throw new Exception(text + " at line: " + lineMarker.Line);
  44. }
  45. void Match(Token tok)
  46. {
  47. if (lastToken != tok)
  48. Error("Expect " + tok + " got " + lastToken);
  49. }
  50. public void Exec()
  51. {
  52. exit = false;
  53. GetNextToken();
  54. while (!exit) Line();
  55. }
  56. Token GetNextToken()
  57. {
  58. prevToken = lastToken;
  59. lastToken = lex.GetToken();
  60. if (lastToken == Token.EOF && prevToken == Token.EOF)
  61. Error("Unexpected end of file");
  62. return lastToken;
  63. }
  64. void Line()
  65. {
  66. while (lastToken == Token.NewLine) GetNextToken();
  67. if (lastToken == Token.EOF)
  68. {
  69. exit = true;
  70. return;
  71. }
  72. lineMarker = lex.TokenMarker;
  73. Statment();
  74. if (lastToken != Token.NewLine && lastToken != Token.EOF)
  75. Error("Expect new line got " + lastToken);
  76. }
  77. void Statment()
  78. {
  79. Token keyword = lastToken;
  80. GetNextToken();
  81. if (KeywordMethods.ContainsKey(keyword))
  82. KeywordMethods[keyword]();
  83. else
  84. {
  85. switch (keyword)
  86. {
  87. case Token.Input: Input(); break;
  88. case Token.Function:
  89. case Token.Global:
  90. case Token.Dim:
  91. case Token.Const:
  92. while (GetNextToken() != Token.NewLine) { }
  93. break;
  94. case Token.Identifer:
  95. if (lastToken == Token.Equal) Let();
  96. else goto default;
  97. break;
  98. case Token.EOF:
  99. exit = true;
  100. break;
  101. default:
  102. Error("Expect keyword got " + keyword);
  103. break;
  104. }
  105. }
  106. if (lastToken == Token.Colon)
  107. {
  108. GetNextToken();
  109. Statment();
  110. }
  111. }
  112. #region Functions
  113. private Dictionary<string, BasicFunction> FunctionDictionary { get; set; }
  114. private void GenerateFunctionDictionary()
  115. {
  116. FunctionDictionary = new Dictionary<string, BasicFunction>(StringComparer.InvariantCultureIgnoreCase);
  117. foreach (var method in typeof(Interpreter).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
  118. {
  119. var attribute = method.GetCustomAttributes(typeof(BuiltInFunctionAttribute), true).FirstOrDefault() as BuiltInFunctionAttribute;
  120. if (attribute == null)
  121. continue;
  122. FunctionDictionary[attribute.Name] = args => (Value)method.Invoke(this, new object[] { args });
  123. }
  124. }
  125. [BuiltInFunction("str")]
  126. private Value Str(List<Value> args)
  127. {
  128. if (args.Count < 1)
  129. throw new ArgumentException();
  130. return args[0].Convert(ValueType.String);
  131. }
  132. [BuiltInFunction("num")]
  133. private Value Num(List<Value> args)
  134. {
  135. if (args.Count < 1)
  136. throw new ArgumentException();
  137. return args[0].Convert(ValueType.Real);
  138. }
  139. [BuiltInFunction("abs")]
  140. private Value Abs(List<Value> args)
  141. {
  142. if (args.Count < 1)
  143. throw new ArgumentException();
  144. return new Value(Math.Abs(args[0].Real));
  145. }
  146. [BuiltInFunction("min")]
  147. private Value Min(List<Value> args)
  148. {
  149. if (args.Count < 2)
  150. throw new ArgumentException();
  151. return new Value(Math.Min(args[0].Real, args[1].Real));
  152. }
  153. [BuiltInFunction("max")]
  154. private Value Max(List<Value> args)
  155. {
  156. if (args.Count < 2)
  157. throw new ArgumentException();
  158. return new Value(Math.Max(args[0].Real, args[1].Real));
  159. }
  160. [BuiltInFunction("not")]
  161. private Value Not(List<Value> args)
  162. {
  163. if (args.Count < 1)
  164. throw new ArgumentException();
  165. return new Value(args[0].Real == 0 ? 1 : 0);
  166. }
  167. private readonly Random random = new Random();
  168. [BuiltInFunction("rand")]
  169. private Value Rand(List<Value> args)
  170. {
  171. if (args.Count < 2)
  172. throw new ArgumentException();
  173. return new Value(random.Next((int)args[0].Real, (int)args[1].Real - 1));
  174. }
  175. #endregion
  176. #region Keywords
  177. private Dictionary<Token, Action> KeywordMethods { get; set; }
  178. private void GenerateKeywordDictionary()
  179. {
  180. KeywordMethods = new Dictionary<Token, Action>();
  181. foreach (var method in typeof(Interpreter).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
  182. {
  183. var attribute = method.GetCustomAttributes(typeof(TargetKeywordAttribute), true).FirstOrDefault() as TargetKeywordAttribute;
  184. if (attribute == null)
  185. continue;
  186. KeywordMethods[attribute.Token] = () => method.Invoke(this, null);
  187. }
  188. }
  189. [TargetKeyword(Token.Print)]
  190. void Print()
  191. {
  192. console.Write(Expr().ToString());
  193. }
  194. [TargetKeyword(Token.PrintL)]
  195. void PrintL()
  196. {
  197. console.PrintSingleLine(Expr().ToString());
  198. }
  199. [TargetKeyword(Token.DrawLine)]
  200. void DrawLine()
  201. {
  202. console.PrintBar();
  203. }
  204. [TargetKeyword(Token.DrawLineForm)]
  205. void DrawLineForm()
  206. {
  207. console.printCustomBar(Expr().ToString());
  208. }
  209. [TargetKeyword(Token.If)]
  210. private void If()
  211. {
  212. bool result = Expr().BinOp(new Value(0), Token.Equal).Real == 1;
  213. Match(Token.Then);
  214. GetNextToken();
  215. if (result)
  216. {
  217. int i = ifcounter;
  218. while (true)
  219. {
  220. if (lastToken == Token.If)
  221. {
  222. i++;
  223. }
  224. else if (lastToken == Token.Else)
  225. {
  226. if (i == ifcounter)
  227. {
  228. GetNextToken();
  229. return;
  230. }
  231. }
  232. else if (lastToken == Token.EndIf)
  233. {
  234. if (i == ifcounter)
  235. {
  236. GetNextToken();
  237. return;
  238. }
  239. i--;
  240. }
  241. GetNextToken();
  242. }
  243. }
  244. }
  245. [TargetKeyword(Token.Else)]
  246. private void Else()
  247. {
  248. int i = ifcounter;
  249. while (true)
  250. {
  251. if (lastToken == Token.If)
  252. {
  253. i++;
  254. }
  255. else if (lastToken == Token.EndIf)
  256. {
  257. if (i == ifcounter)
  258. {
  259. GetNextToken();
  260. return;
  261. }
  262. i--;
  263. }
  264. GetNextToken();
  265. }
  266. }
  267. [TargetKeyword(Token.EndIf)]
  268. private void EndIf()
  269. {
  270. }
  271. [TargetKeyword(Token.End)]
  272. private void End()
  273. {
  274. exit = true;
  275. }
  276. [TargetKeyword(Token.Let)]
  277. private void Let()
  278. {
  279. if (lastToken != Token.Equal)
  280. {
  281. Match(Token.Identifer);
  282. GetNextToken();
  283. Match(Token.Equal);
  284. }
  285. string id = lex.Identifer;
  286. GetNextToken();
  287. SetVar(id, Expr());
  288. }
  289. [TargetKeyword(Token.For)]
  290. private void For()
  291. {
  292. Match(Token.Identifer);
  293. string var = lex.Identifer;
  294. GetNextToken();
  295. Match(Token.Equal);
  296. GetNextToken();
  297. Value v = Expr();
  298. if (loops.ContainsKey(var))
  299. {
  300. loops[var] = lineMarker;
  301. }
  302. else
  303. {
  304. SetVar(var, v);
  305. loops.Add(var, lineMarker);
  306. }
  307. Match(Token.To);
  308. GetNextToken();
  309. v = Expr();
  310. if (vars[var].BinOp(v, Token.More).Real == 1)
  311. {
  312. while (true)
  313. {
  314. while (!(GetNextToken() == Token.Identifer && prevToken == Token.Next)) ;
  315. if (lex.Identifer == var)
  316. {
  317. loops.Remove(var);
  318. GetNextToken();
  319. Match(Token.NewLine);
  320. break;
  321. }
  322. }
  323. }
  324. }
  325. [TargetKeyword(Token.Next)]
  326. private void Next()
  327. {
  328. Match(Token.Identifer);
  329. string var = lex.Identifer;
  330. vars[var] = vars[var].BinOp(new Value(1), Token.Plus);
  331. lex.GoTo(new Marker(loops[var].Pointer - 1, loops[var].Line, loops[var].Column - 1));
  332. lastToken = Token.NewLine;
  333. }
  334. #endregion
  335. void Input()
  336. {
  337. while (true)
  338. {
  339. Match(Token.Identifer);
  340. if (!vars.ContainsKey(lex.Identifer)) vars.Add(lex.Identifer, new Value());
  341. console.WaitInput(new Core.Interop.InputRequest() { InputType = Core.Interop.InputType.StrValue });
  342. string input = console.LastInput;
  343. double d;
  344. if (double.TryParse(input, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d))
  345. vars[lex.Identifer] = new Value(d);
  346. else
  347. vars[lex.Identifer] = new Value(input);
  348. GetNextToken();
  349. if (lastToken != Token.Comma) break;
  350. GetNextToken();
  351. }
  352. }
  353. Value Expr()
  354. {
  355. Dictionary<Token, int> prec = new Dictionary<Token, int>()
  356. {
  357. { Token.Or, 0 }, { Token.And, 0 },
  358. { Token.Equal, 1 }, { Token.NotEqual, 1 },
  359. { Token.Less, 1 }, { Token.More, 1 }, { Token.LessEqual, 1 }, { Token.MoreEqual, 1 },
  360. { Token.Plus, 2 }, { Token.Minus, 2 },
  361. { Token.Asterisk, 3 }, {Token.Slash, 3 },
  362. { Token.Caret, 4 }
  363. };
  364. Stack<Value> stack = new Stack<Value>();
  365. Stack<Token> operators = new Stack<Token>();
  366. int i = 0;
  367. while (true)
  368. {
  369. if (lastToken == Token.Value)
  370. {
  371. stack.Push(lex.Value);
  372. }
  373. else if (lastToken == Token.Identifer)
  374. {
  375. if (vars.ContainsKey(lex.Identifer))
  376. {
  377. stack.Push(vars[lex.Identifer]);
  378. }
  379. else if (FunctionDictionary.ContainsKey(lex.Identifer))
  380. {
  381. string name = lex.Identifer;
  382. List<Value> args = new List<Value>();
  383. GetNextToken();
  384. Match(Token.LParen);
  385. start:
  386. if (GetNextToken() != Token.RParen)
  387. {
  388. args.Add(Expr());
  389. if (lastToken == Token.Comma)
  390. goto start;
  391. }
  392. stack.Push(FunctionDictionary[name](args));
  393. }
  394. else
  395. {
  396. Error("Undeclared variable " + lex.Identifer);
  397. }
  398. }
  399. else if (lastToken == Token.LParen)
  400. {
  401. GetNextToken();
  402. stack.Push(Expr());
  403. Match(Token.RParen);
  404. }
  405. else if (lastToken >= Token.Plus && lastToken <= Token.Not)
  406. {
  407. if ((lastToken == Token.Minus || lastToken == Token.Minus) && (i == 0 || prevToken == Token.LParen))
  408. {
  409. stack.Push(new Value(0));
  410. operators.Push(lastToken);
  411. }
  412. else
  413. {
  414. while (operators.Count > 0 && prec[lastToken] <= prec[operators.Peek()])
  415. Operation(ref stack, operators.Pop());
  416. operators.Push(lastToken);
  417. }
  418. }
  419. else
  420. {
  421. if (i == 0)
  422. Error("Empty expression");
  423. break;
  424. }
  425. i++;
  426. GetNextToken();
  427. }
  428. while (operators.Count > 0)
  429. Operation(ref stack, operators.Pop());
  430. return stack.Pop();
  431. }
  432. void Operation(ref Stack<Value> stack, Token token)
  433. {
  434. Value b = stack.Pop();
  435. Value a = stack.Pop();
  436. Value result = a.BinOp(b, token);
  437. stack.Push(result);
  438. }
  439. }
  440. }