private KecaknoahForAstNode ParseFor(Queue<KecaknoahToken> tokens, bool single) { var result = new KecaknoahForAstNode(); var t = tokens.Peek(); if (t.Type == KecaknoahTokenType.Identifer) { tokens.Dequeue(); result.Name = t.TokenString; } else { result.Name = Guid.NewGuid().ToString().Substring(0, 8); } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenStart)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("forの各式は全体をカッコでくくってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { var exp = ParseExpression(tokens); result.InitializeExpressions.Add(exp); if (tokens.CheckSkipToken(KecaknoahTokenType.Semicolon)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("初期化式はコンマで区切ってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 result.Condition = ParseExpression(tokens); if (!tokens.CheckSkipToken(KecaknoahTokenType.Semicolon)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("セミコロンで区切ってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 while (true) { var exp = ParseExpression(tokens); result.CounterExpressions.Add(exp); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 if (tokens.CheckToken(KecaknoahTokenType.ParenEnd)) break; if (!tokens.CheckSkipToken(KecaknoahTokenType.Comma)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("初期化式はコンマで区切ってください。")); tokens.SkipLogicalLineBreak(); //TODO: 暗黙改行 } if (!tokens.CheckSkipToken(KecaknoahTokenType.ParenEnd)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("forの各式は全体をカッコでくくってください。")); if (single || !tokens.SkipLogicalLineBreak()) { if (tokens.SkipLogicalLineBreak()) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("単行for文のみ記述できます。")); foreach (var i in ParseSingleLineStatement(tokens)) result.AddNode(i); } else { foreach (var i in ParseBlock(tokens)) result.AddNode(i); if (!tokens.CheckSkipToken(KecaknoahTokenType.NextKeyword)) throw new KecaknoahParseException(tokens.Dequeue().CreateErrorAt("nextで終わっていません。")); } return result; }
private IList<KecaknoahILCode> PrecompileFor(KecaknoahForAstNode fn) { var id = Guid.NewGuid().ToString().Substring(0, 8); var result = new List<KecaknoahILCode>(); foreach (var i in fn.InitializeExpressions) { result.AddRange(PrecompileExpression(i)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-Next" }); result.AddRange(PrecompileExpression(fn.Condition)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.FalseJump, StringValue = $"{id}-End" }); result.AddRange(PrecompileBlock(fn.Children, id)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-Continue" }); foreach (var i in fn.CounterExpressions) { result.AddRange(PrecompileExpression(i)); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Pop }); } result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Jump, StringValue = $"{id}-Next" }); result.Add(new KecaknoahILCode { Type = KecaknoahILCodeType.Label, StringValue = $"{id}-End" }); return result; }