添加对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, And,
Or, Or,
True, True,
False False,
While
} }
public enum OperatorType public enum OperatorType

File diff suppressed because it is too large Load Diff

View File

@ -348,6 +348,7 @@ public static class PascalGrammar
// | CompoundStatement // | CompoundStatement
// | if Expression then Statement ElsePart // | if Expression then Statement ElsePart
// | for id AssignOp Expression to Expression do Statement // | for id AssignOp Expression to Expression do Statement
// | while Expression do Statement
// 注意这里 read 和 write 作为普通的函数调用处理了 // 注意这里 read 和 write 作为普通的函数调用处理了
// 因此下面并没有单独声明 // 因此下面并没有单独声明
new NonTerminator(NonTerminatorType.Statement), [ new NonTerminator(NonTerminatorType.Statement), [
@ -387,6 +388,13 @@ public static class PascalGrammar
new NonTerminator(NonTerminatorType.Expression), new NonTerminator(NonTerminatorType.Expression),
new Terminator(KeywordType.Do), new Terminator(KeywordType.Do),
new NonTerminator(NonTerminatorType.Statement) 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 }, { "and", KeywordType.And },
{ "or", KeywordType.Or }, { "or", KeywordType.Or },
{ "true", KeywordType.True }, { "true", KeywordType.True },
{ "false", KeywordType.False } { "false", KeywordType.False },
{ "while", KeywordType.While }
}; };
public static bool GetKeywordTypeByKeywprd(string keyword, out KeywordType type) 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) public override void PostVisit(Expression expression)
{ {
base.PostVisit(expression); base.PostVisit(expression);
@ -333,6 +345,11 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
{ {
_forEndConditions.Push(expression.VariableName); _forEndConditions.Push(expression.VariableName);
} }
if (expression.IsWhileCondition)
{
_whileConditionNames.Push(expression.VariableName);
}
} }
@ -386,6 +403,21 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
/// </summary> /// </summary>
private readonly Stack<string> _forEndLabels = new(); 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) public override void PreVisit(Statement statement)
{ {
base.PreVisit(statement); base.PreVisit(statement);
@ -396,8 +428,15 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
{ {
e.Begin.IsForConditionBegin = true; e.Begin.IsForConditionBegin = true;
e.End.IsForConditionEnd = true; e.End.IsForConditionEnd = true;
e.Do.IsForNode = true;
_forVariables.Push(e.Iterator.IdentifierName); _forVariables.Push(e.Iterator.IdentifierName);
}; };
statement.OnWhileGenerator += (_, e) =>
{
e.Do.IsWhileNode = true;
e.Condition.IsWhileCondition = true;
};
} }
public override void PostVisit(Statement statement) public override void PostVisit(Statement statement)
@ -434,6 +473,17 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
_forBeginConditions.Pop(); _forBeginConditions.Pop();
_forEndConditions.Pop(); _forEndConditions.Pop();
}; };
statement.OnWhileGenerator += (_, _) =>
{
Builder.AddLine($"""
goto {_whileBeginLabels.Peek()};
{_whileEndLabels.Peek()}:;
""");
_whileBeginLabels.Pop();
_whileEndLabels.Pop();
_whileConditionNames.Pop();
};
} }
public override void PreVisit(ElsePart elsePart) public override void PreVisit(ElsePart elsePart)
@ -605,6 +655,8 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
"""); """);
break; break;
case KeywordType.Do: case KeywordType.Do:
if (terminatedSyntaxNode.IsForNode)
{
Builder.AddLine($""" Builder.AddLine($"""
if ({_forVariables.Peek()} <= {_forEndConditions.Peek()}) if ({_forVariables.Peek()} <= {_forEndConditions.Peek()})
goto {_forLabels.Peek()}; goto {_forLabels.Peek()};
@ -612,6 +664,17 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
goto {_forEndLabels.Peek()}; goto {_forEndLabels.Peek()};
{_forLabels.Peek()}:; {_forLabels.Peek()}:;
"""); """);
}
if (terminatedSyntaxNode.IsWhileNode)
{
// GenerateWhileLabel();
Builder.AddLine($"""
if (!{_whileConditionNames.Peek()})
goto {_whileEndLabels.Peek()};
""");
}
break; break;
} }
} }
@ -881,4 +944,16 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
_labelCount += 1; _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()); 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) public override void PostVisit(ProcedureCall procedureCall)

View File

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

View File

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

View File

@ -7,6 +7,16 @@ public class TerminatedSyntaxNode : SyntaxNodeBase
{ {
public override bool IsTerminated => true; 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) public override void PreVisit(SyntaxNodeVisitor visitor)
{ {
visitor.PreVisit(this); visitor.PreVisit(this);

View File

@ -243,4 +243,19 @@ public class PascalGrammarTests
CompilerHelpers.Analyse(program); 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("DO", KeywordType.Do)]
[InlineData("true", KeywordType.True)] [InlineData("true", KeywordType.True)]
[InlineData("false", KeywordType.False)] [InlineData("false", KeywordType.False)]
[InlineData("while",KeywordType.While)]
public void SmokeTest(string input, KeywordType type) public void SmokeTest(string input, KeywordType type)
{ {
IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input)); IEnumerable<SemanticToken> tokensEnumerable = _lexer.Tokenize(new StringSourceReader(input));