添加对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,
|
And,
|
||||||
Or,
|
Or,
|
||||||
True,
|
True,
|
||||||
False
|
False,
|
||||||
|
While
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OperatorType
|
public enum OperatorType
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user