add: for & if & while support.

This commit is contained in:
jackfiled 2024-08-17 20:29:57 +08:00
parent 97f9fb9ec3
commit c44b720e09
7 changed files with 187 additions and 2 deletions

View File

@ -150,13 +150,56 @@ public sealed class GrammarParser : GrammarParserBuilder
); );
} }
public static IParser<LexicalToken, IfNode> IfParser()
{
IParser<LexicalToken, IfNode> commonPart = from _ in Keyword("if")
from condition in ExpressionParser()
from _1 in Keyword("then")
from statement in StatementParser()
select new IfNode(condition, statement);
return Choice(
from common in commonPart
from _ in Keyword("else")
from elseStatement in StatementParser()
select new IfNode(common.Condition, common.Statement, elseStatement),
commonPart
);
}
public static IParser<LexicalToken, ForNode> ForParser()
{
return from _ in Keyword("for")
from identifier in IdentifierParser()
from _1 in Operator(":=")
from left in ExpressionParser()
from _2 in Keyword("to")
from right in ExpressionParser()
from _3 in Keyword("do")
from statement in StatementParser()
select new ForNode(identifier, left, right, statement);
}
public static IParser<LexicalToken, WhileNode> WhileParser()
{
return from _ in Keyword("while")
from condition in ExpressionParser()
from _1 in Keyword("do")
from statement in StatementParser()
select new WhileNode(condition, statement);
}
public static IParser<LexicalToken, SyntaxNodeBase> StatementParser() public static IParser<LexicalToken, SyntaxNodeBase> StatementParser()
{ {
return Choice( return Choice<LexicalToken, SyntaxNodeBase>(
from variable in VariableParser() from variable in VariableParser()
from _ in Operator(":=") from _ in Operator(":=")
from expression in ExpressionParser() from expression in ExpressionParser()
select new AssignNode(variable, expression) select new AssignNode(variable, expression),
IfParser(),
ForParser(),
WhileParser(),
CompoundStatementParser()
); );
} }

View File

@ -0,0 +1,20 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class ForNode(
LexicalToken identifier,
SyntaxNodeBase leftCondition,
SyntaxNodeBase rightCondition,
SyntaxNodeBase statement) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.For;
public LexicalToken Identifier => identifier;
public SyntaxNodeBase LeftCondition => leftCondition;
public SyntaxNodeBase RightCondition => rightCondition;
public SyntaxNodeBase Statement => statement;
}

View File

@ -0,0 +1,26 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class IfNode : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.If;
public SyntaxNodeBase Condition { get; }
public SyntaxNodeBase Statement { get; }
public SyntaxNodeBase? ElseStatement { get; }
public IfNode(SyntaxNodeBase condition, SyntaxNodeBase statement)
{
Condition = condition;
Statement = statement;
ElseStatement = null;
}
public IfNode(SyntaxNodeBase condition, SyntaxNodeBase statement, SyntaxNodeBase elseStatement)
{
Condition = condition;
Statement = statement;
ElseStatement = elseStatement;
}
}

View File

@ -14,6 +14,9 @@ public enum SyntaxNodeType
Block, Block,
Constant, Constant,
VariableDeclaration, VariableDeclaration,
If,
While,
For,
ProgramBody, ProgramBody,
ProgramHead, ProgramHead,
Program Program

View File

@ -0,0 +1,10 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class WhileNode(SyntaxNodeBase condition, SyntaxNodeBase statement) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.While;
public SyntaxNodeBase Condition => condition;
public SyntaxNodeBase Statement => statement;
}

View File

@ -138,6 +138,21 @@ public class ProgramParserTests : GrammarParserTestBase
a[10,0] := 1; a[10,0] := 1;
end. end.
""")] """)]
[InlineData("""
program main;
begin
begin
end
end.
""")]
[InlineData("""
program main;
var i : integer;
begin
while i < 10 do
i := i + 1;
end.
""")]
public void ProgramParseTest(string input) public void ProgramParseTest(string input)
{ {
ProgramParse(input); ProgramParse(input);

View File

@ -15,6 +15,74 @@ public class StatementParserTests : GrammarParserTestBase
Assert.Equal(1, node.Expression.Convert<IntegerValueNode>().Value); Assert.Equal(1, node.Expression.Convert<IntegerValueNode>().Value);
} }
[Fact]
public void IfTest1()
{
IfNode node = RunParser<IfNode>(GrammarParser.IfParser(), """
if i = 1 then
a := a + 1
else
a := a + 2
""");
Assert.NotNull(node.ElseStatement);
BinaryOperatorNode condition = node.Condition.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.Equal, condition.OperatorType);
AssignNode statement = node.Statement.Convert<AssignNode>();
Assert.Equal("a", statement.Variable.Identifier.LiteralValue);
AssignNode elseStatement = node.Statement.Convert<AssignNode>();
Assert.Equal("a", elseStatement.Variable.Identifier.LiteralValue);
}
[Fact]
public void IfTest2()
{
IfNode node = RunParser<IfNode>(GrammarParser.IfParser(), """
if i = 1 then
if i = 2 then
a := a + 1
else
a := a + 2
""");
Assert.Null(node.ElseStatement);
IfNode subIfNode = node.Statement.Convert<IfNode>();
Assert.NotNull(subIfNode.ElseStatement);
}
[Fact]
public void ForTest1()
{
ForNode node = RunParser<ForNode>(GrammarParser.ForParser(), """
for i := 1 to 10 do
a := a + i
""");
Assert.Equal("i", node.Identifier.LiteralValue);
Assert.Equal(1, node.LeftCondition.Convert<IntegerValueNode>().Value);
Assert.Equal(10, node.RightCondition.Convert<IntegerValueNode>().Value);
AssignNode assignNode = node.Statement.Convert<AssignNode>();
Assert.Equal("a", assignNode.Variable.Identifier.LiteralValue);
}
[Fact]
public void WhileTest1()
{
WhileNode node = RunParser<WhileNode>(GrammarParser.WhileParser(), """
while c >= 1 do
a := a + 1;
""");
BinaryOperatorNode binaryOperatorNode = node.Condition.Convert<BinaryOperatorNode>();
Assert.Equal(BinaryOperatorType.GreaterEqual, binaryOperatorNode.OperatorType);
AssignNode assignNode = node.Statement.Convert<AssignNode>();
Assert.Equal("a", assignNode.Variable.Identifier.LiteralValue);
}
[Theory] [Theory]
[InlineData(""" [InlineData("""
begin begin