添加对while-do语句的支持 (#77)

Co-authored-by: jackfiled <xcrenchangjun@outlook.com>
Reviewed-on: PostGuard/Canon#77
Co-authored-by: ichirinko <1621543655@qq.com>
Co-committed-by: ichirinko <1621543655@qq.com>
This commit is contained in:
ichirinko 2024-05-10 13:52:11 +08:00 committed by jackfiled
parent 4a712fc462
commit f993d49856
11 changed files with 867 additions and 704 deletions

View File

@ -65,7 +65,8 @@ public enum KeywordType
And,
Or,
True,
False
False,
While
}
public enum OperatorType

File diff suppressed because it is too large Load Diff

View File

@ -348,6 +348,7 @@ public static class PascalGrammar
// | CompoundStatement
// | if Expression then Statement ElsePart
// | for id AssignOp Expression to Expression do Statement
// | while Expression do Statement
// 注意这里 read 和 write 作为普通的函数调用处理了
// 因此下面并没有单独声明
new NonTerminator(NonTerminatorType.Statement), [
@ -387,6 +388,13 @@ public static class PascalGrammar
new NonTerminator(NonTerminatorType.Expression),
new Terminator(KeywordType.Do),
new NonTerminator(NonTerminatorType.Statement)
],
[
// while Expression do Statement
new Terminator(KeywordType.While),
new NonTerminator(NonTerminatorType.Expression),
new Terminator(KeywordType.Do),
new NonTerminator(NonTerminatorType.Statement)
]
]
},

View File

@ -33,7 +33,8 @@ public static class LexRules
{ "and", KeywordType.And },
{ "or", KeywordType.Or },
{ "true", KeywordType.True },
{ "false", KeywordType.False }
{ "false", KeywordType.False },
{ "while", KeywordType.While }
};
public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type)

View File

@ -294,6 +294,18 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
};
}
public override void PreVisit(Expression expression)
{
base.PreVisit(expression);
if (expression.IsWhileCondition)
{
GenerateWhileLabel();
Builder.AddLine($"""
{_whileBeginLabels.Peek()}:;
""");
}
}
public override void PostVisit(Expression expression)
{
base.PostVisit(expression);
@ -333,6 +345,11 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
{
_forEndConditions.Push(expression.VariableName);
}
if (expression.IsWhileCondition)
{
_whileConditionNames.Push(expression.VariableName);
}
}
@ -386,6 +403,21 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
/// </summary>
private readonly Stack<string> _forEndLabels = new();
/// <summary>
/// WHILE语句条件变量的标签
/// </summary>
private readonly Stack<string> _whileConditionNames = new();
/// <summary>
/// WHILE语句开始的标签
/// </summary>
private readonly Stack<string> _whileBeginLabels = new();
/// <summary>
/// WHILE语句结束的标签
/// </summary>
private readonly Stack<string> _whileEndLabels = new();
public override void PreVisit(Statement statement)
{
base.PreVisit(statement);
@ -396,8 +428,15 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
{
e.Begin.IsForConditionBegin = true;
e.End.IsForConditionEnd = true;
e.Do.IsForNode = true;
_forVariables.Push(e.Iterator.IdentifierName);
};
statement.OnWhileGenerator += (_, e) =>
{
e.Do.IsWhileNode = true;
e.Condition.IsWhileCondition = true;
};
}
public override void PostVisit(Statement statement)
@ -434,6 +473,17 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
_forBeginConditions.Pop();
_forEndConditions.Pop();
};
statement.OnWhileGenerator += (_, _) =>
{
Builder.AddLine($"""
goto {_whileBeginLabels.Peek()};
{_whileEndLabels.Peek()}:;
""");
_whileBeginLabels.Pop();
_whileEndLabels.Pop();
_whileConditionNames.Pop();
};
}
public override void PreVisit(ElsePart elsePart)
@ -605,13 +655,26 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
""");
break;
case KeywordType.Do:
Builder.AddLine($"""
if ({_forVariables.Peek()} <= {_forEndConditions.Peek()})
goto {_forLabels.Peek()};
else
goto {_forEndLabels.Peek()};
{_forLabels.Peek()}:;
""");
if (terminatedSyntaxNode.IsForNode)
{
Builder.AddLine($"""
if ({_forVariables.Peek()} <= {_forEndConditions.Peek()})
goto {_forLabels.Peek()};
else
goto {_forEndLabels.Peek()};
{_forLabels.Peek()}:;
""");
}
if (terminatedSyntaxNode.IsWhileNode)
{
// GenerateWhileLabel();
Builder.AddLine($"""
if (!{_whileConditionNames.Peek()})
goto {_whileEndLabels.Peek()};
""");
}
break;
}
}
@ -881,4 +944,16 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
_labelCount += 1;
}
/// <summary>
/// 产生WHILE语句中的标签
/// </summary>
private void GenerateWhileLabel()
{
_whileBeginLabels.Push($"while_{_labelCount}");
_whileConditionNames.Push($"while_condition_{_labelCount}");
_whileEndLabels.Push($"while_end_{_labelCount}");
_labelCount += 1;
}
}

View File

@ -478,6 +478,18 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
e.Condition.VariableType.ToString());
}
};
// statement -> while Expression do Statement
statement.OnWhileGenerator += (_, e) =>
{
// 条件是否为Boolean
if (e.Condition.VariableType != PascalBasicType.Boolean)
{
IsError = true;
logger?.LogError("Expect '{}' but '{}'.", PascalBasicType.Boolean.TypeName,
e.Condition.VariableType.ToString());
}
};
}
public override void PostVisit(ProcedureCall procedureCall)

View File

@ -48,6 +48,11 @@ public class Expression : NonTerminatedSyntaxNode
/// </summary>
public bool IsIfCondition { get; set; }
/// <summary>
/// 是否为WHILE语句中的条件语句
/// </summary>
public bool IsWhileCondition { get; set; }
/// <summary>
/// 直接赋值产生式的事件
/// </summary>

View File

@ -29,6 +29,17 @@ public class ForGeneratorEventArgs : EventArgs
public required Expression End { get; init; }
public required Statement Sentence { get; init; }
public required TerminatedSyntaxNode Do { get; init; }
}
public class WhileGeneratorEventArgs : EventArgs
{
public required Expression Condition { get; init; }
public required Statement Sentence { get; init; }
public required TerminatedSyntaxNode Do { get; init; }
}
public class Statement : NonTerminatedSyntaxNode
@ -62,6 +73,11 @@ public class Statement : NonTerminatedSyntaxNode
/// </summary>
public event EventHandler<ForGeneratorEventArgs>? OnForGenerator;
/// <summary>
/// 使用While产生式的事件
/// </summary>
public event EventHandler<WhileGeneratorEventArgs>? OnWhileGenerator;
public static Statement Create(List<SyntaxNodeBase> children)
{
return new Statement { Children = children };
@ -77,6 +93,16 @@ public class Statement : NonTerminatedSyntaxNode
Variable = Children[0].Convert<Variable>(), Expression = Children[2].Convert<Expression>()
});
}
else if (Children.Count == 4)
{
OnWhileGenerator?.Invoke(this,
new WhileGeneratorEventArgs
{
Condition = Children[1].Convert<Expression>(),
Do = Children[2].Convert<TerminatedSyntaxNode>(),
Sentence = Children[3].Convert<Statement>(),
});
}
else if (Children.Count == 5)
{
OnIfGenerator?.Invoke(this,
@ -95,6 +121,7 @@ public class Statement : NonTerminatedSyntaxNode
Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
Begin = Children[3].Convert<Expression>(),
End = Children[5].Convert<Expression>(),
Do = Children[6].Convert<TerminatedSyntaxNode>(),
Sentence = Children[7].Convert<Statement>()
});
}

View File

@ -7,6 +7,16 @@ public class TerminatedSyntaxNode : SyntaxNodeBase
{
public override bool IsTerminated => true;
/// <summary>
/// 是否为For循环定义中的DO节点
/// </summary>
public bool IsForNode { get; set; }
/// <summary>
/// 是否为While循环定义中的DO节点
/// </summary>
public bool IsWhileNode { get; set; }
public override void PreVisit(SyntaxNodeVisitor visitor)
{
visitor.PreVisit(this);

View File

@ -243,4 +243,19 @@ public class PascalGrammarTests
CompilerHelpers.Analyse(program);
}
[Fact]
public void WhileLoopTest()
{
const string program = """
program main;
var i : integer;
begin
while i < 10 do
i := i + 1;
end.
""";
CompilerHelpers.Analyse(program);
}
}

View File

@ -28,6 +28,7 @@ public class KeywordTypeTests
[InlineData("DO", KeywordType.Do)]
[InlineData("true", KeywordType.True)]
[InlineData("false", KeywordType.False)]
[InlineData("while",KeywordType.While)]
public void SmokeTest(string input, KeywordType type)
{
IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input));