添加对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:
parent
4a712fc462
commit
f993d49856
|
@ -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
|
@ -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)
|
||||
]
|
||||
]
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,6 +655,8 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
|
|||
""");
|
||||
break;
|
||||
case KeywordType.Do:
|
||||
if (terminatedSyntaxNode.IsForNode)
|
||||
{
|
||||
Builder.AddLine($"""
|
||||
if ({_forVariables.Peek()} <= {_forEndConditions.Peek()})
|
||||
goto {_forLabels.Peek()};
|
||||
|
@ -612,6 +664,17 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -48,6 +48,11 @@ public class Expression : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public bool IsIfCondition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为WHILE语句中的条件语句
|
||||
/// </summary>
|
||||
public bool IsWhileCondition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
|
|
|
@ -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>()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue
Block a user