feat: Grammar Parser (#3)

Reviewed-on: https://git.bupt-hpc.cn/jackfiled/CanonSharp/pulls/3
Co-authored-by: jackfiled <xcrenchangjun@outlook.com>
Co-committed-by: jackfiled <xcrenchangjun@outlook.com>
This commit is contained in:
2024-08-18 12:01:27 +08:00
committed by 任昌骏
parent 3ed8bf5d36
commit cf19f8197e
85 changed files with 2340 additions and 413 deletions

View File

@@ -0,0 +1,10 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class AssignNode(VariableNode variable, SyntaxNodeBase expression) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Assign;
public VariableNode Variable => variable;
public SyntaxNodeBase Expression => expression;
}

View File

@@ -0,0 +1,33 @@
namespace CanonSharp.Pascal.SyntaxTree;
public enum BinaryOperatorType
{
Add,
Subtract,
Multiply,
// Pascal特有的整数除法关键词div
IntegerDivide,
Divide,
Mod,
And,
Or,
Equal,
NotEqual,
Greater,
GreaterEqual,
Less,
LessEqual
}
public sealed class BinaryOperatorNode(BinaryOperatorType operatorType, SyntaxNodeBase left, SyntaxNodeBase right)
: SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.BinaryOperator;
public BinaryOperatorType OperatorType => operatorType;
public SyntaxNodeBase Left => left;
public SyntaxNodeBase Right => right;
}

View File

@@ -0,0 +1,8 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class BlockNode(IEnumerable<SyntaxNodeBase> statements) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Block;
public IList<SyntaxNodeBase> Statements => statements.ToList();
}

View File

@@ -0,0 +1,8 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class BooleanValueNode(bool value) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.BooleanValue;
public bool Value => value;
}

View File

@@ -0,0 +1,8 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class CharValueNode(char value) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.CharValue;
public char Value => value;
}

View File

@@ -0,0 +1,12 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class ConstantNode(LexicalToken identifier, SyntaxNodeBase value) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Constant;
public LexicalToken Identifier = identifier;
public SyntaxNodeBase Value = value;
}

View File

@@ -0,0 +1,8 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class FloatValueNode(double value) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.FloatValue;
public double Value => value;
}

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

@@ -0,0 +1,8 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class IntegerValueNode(int value) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.IntegerValue;
public int Value => value;
}

View File

@@ -0,0 +1,14 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class Parameter(bool isReference, LexicalToken identifier, SyntaxNodeBase typeNode) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Parameter;
public bool IsReference => isReference;
public LexicalToken Identifier => identifier;
public SyntaxNodeBase TypeNode => typeNode;
}

View File

@@ -0,0 +1,18 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class ProcedureCallNode : SyntaxNodeBase
{
public ProcedureCallNode(LexicalToken identifier, IEnumerable<SyntaxNodeBase> parameters)
{
Identifier = identifier;
Parameters.AddRange(parameters);
}
public override SyntaxNodeType NodeType => SyntaxNodeType.ProcedureCall;
public LexicalToken Identifier { get; }
public List<SyntaxNodeBase> Parameters { get; } = [];
}

View File

@@ -0,0 +1,10 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class Program(ProgramHead head, ProgramBody body) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Program;
public ProgramHead Head => head;
public ProgramBody Body => body;
}

View File

@@ -0,0 +1,17 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class ProgramBody(BlockNode constantDeclarations, BlockNode variableDeclarations,
BlockNode subprograms,
BlockNode mainBlock)
: SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.ProgramBody;
public BlockNode ConstantDeclarations => constantDeclarations;
public BlockNode VariableDeclarations => variableDeclarations;
public BlockNode Subprograms => subprograms;
public BlockNode MainBlock => mainBlock;
}

View File

@@ -0,0 +1,10 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class ProgramHead(LexicalToken programName) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.ProgramHead;
public LexicalToken ProgramName => programName;
}

View File

@@ -0,0 +1,10 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class Subprogram(SubprogramHead subprogramHead, SubprogramBody subprogramBody) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.SubProgram;
public SubprogramHead Head => subprogramHead;
public SubprogramBody Body => subprogramBody;
}

View File

@@ -0,0 +1,12 @@
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class SubprogramBody(BlockNode constDeclarations, BlockNode variableDeclarations, BlockNode mainBlock) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.SubprogramBody;
public BlockNode ConstDeclarations => constDeclarations;
public BlockNode VariableDeclarations => variableDeclarations;
public BlockNode MainBlock => mainBlock;
}

View File

@@ -0,0 +1,28 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class SubprogramHead : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.SubprogramHead;
public LexicalToken Identifier { get; }
public List<Parameter> Parameters { get; } = [];
public SyntaxNodeBase? TypeToken { get; }
public SubprogramHead(LexicalToken identifier, IEnumerable<Parameter> parameters)
{
Identifier = identifier;
Parameters.AddRange(parameters);
TypeToken = null;
}
public SubprogramHead(LexicalToken identifier, IEnumerable<Parameter> parameters, SyntaxNodeBase typeToken) : this(
identifier, parameters)
{
TypeToken = typeToken;
}
}

View File

@@ -0,0 +1,43 @@
namespace CanonSharp.Pascal.SyntaxTree;
public enum SyntaxNodeType
{
BinaryOperator,
UnaryOperator,
IntegerValue,
FloatValue,
BooleanValue,
CharValue,
Variable,
Type,
Assign,
Block,
Constant,
VariableDeclaration,
If,
While,
For,
ProcedureCall,
Parameter,
SubprogramHead,
SubprogramBody,
SubProgram,
ProgramBody,
ProgramHead,
Program
}
public abstract class SyntaxNodeBase
{
public abstract SyntaxNodeType NodeType { get; }
public T Convert<T>() where T : SyntaxNodeBase
{
if (this is not T result)
{
throw new InvalidCastException($"Can't convert {NodeType} to target node.");
}
return result;
}
}

View File

@@ -0,0 +1,24 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public record struct ArrayRange(int Left, int Right);
public sealed class TypeNode : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Type;
public LexicalToken TypeToken { get; }
public List<ArrayRange> ArrayRanges { get; } = [];
public TypeNode(LexicalToken typeToken)
{
TypeToken = typeToken;
}
public TypeNode(LexicalToken typeToken, IEnumerable<ArrayRange> arrayRanges) : this(typeToken)
{
ArrayRanges.AddRange(arrayRanges);
}
}

View File

@@ -0,0 +1,17 @@
namespace CanonSharp.Pascal.SyntaxTree;
public enum UnaryOperatorType
{
Plus,
Minus,
Not
}
public sealed class UnaryOperatorNode(UnaryOperatorType operatorType, SyntaxNodeBase node) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.UnaryOperator;
public UnaryOperatorType OperatorType => operatorType;
public SyntaxNodeBase Node => node;
}

View File

@@ -0,0 +1,12 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class VariableDeclarationNode(IEnumerable<LexicalToken> identifiers, TypeNode typeNode) : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.VariableDeclaration;
public IList<LexicalToken> Identifiers => identifiers.ToList();
public TypeNode TypeNode => typeNode;
}

View File

@@ -0,0 +1,23 @@
using CanonSharp.Pascal.Scanner;
namespace CanonSharp.Pascal.SyntaxTree;
public sealed class VariableNode : SyntaxNodeBase
{
public override SyntaxNodeType NodeType => SyntaxNodeType.Variable;
public LexicalToken Identifier { get; }
public List<SyntaxNodeBase> Indexers { get; } = [];
public VariableNode(LexicalToken identifier)
{
Identifier = identifier;
}
public VariableNode(LexicalToken identifier, IEnumerable<SyntaxNodeBase> expressions)
{
Identifier = identifier;
Indexers.AddRange(expressions);
}
}

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;
}