From 8d30b1626b6c53b7ea32105c00a065ed3c32f3dd Mon Sep 17 00:00:00 2001 From: jackfiled Date: Sat, 9 Mar 2024 23:57:43 +0800 Subject: [PATCH] add: Terminator and Expression --- Canon.Core/Enums/GrammarEnums.cs | 37 +++++++ Canon.Core/GrammarParser/Expression.cs | 78 ++++++++++++++ Canon.Core/GrammarParser/Terminator.cs | 137 +++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 Canon.Core/Enums/GrammarEnums.cs create mode 100644 Canon.Core/GrammarParser/Expression.cs create mode 100644 Canon.Core/GrammarParser/Terminator.cs diff --git a/Canon.Core/Enums/GrammarEnums.cs b/Canon.Core/Enums/GrammarEnums.cs new file mode 100644 index 0000000..e438969 --- /dev/null +++ b/Canon.Core/Enums/GrammarEnums.cs @@ -0,0 +1,37 @@ +namespace Canon.Core.Enums; + +public enum NonTerminatorType +{ + ProgramStruct, + ProgramHead, + ProgramBody, + IdentifierList, + ConstDeclarations, + VarDeclarations, + SubprogramDeclarations, + CompoundStatement, + ConstDeclaration, + ConstValue, + VarDeclaration, + Type, + BasicType, + Range, + Subprogram, + SubprogramHead, + SubprogramBody, + FormalParameter, + ParameterList, + Parameter, + VarParameter, + ValueParameter, + StatementList, + Statement, + Variable, + Expression, + ProcedureCall, + ElsePart, + ExpressionList, + SimpleExpression, + Term, + Factor +} diff --git a/Canon.Core/GrammarParser/Expression.cs b/Canon.Core/GrammarParser/Expression.cs new file mode 100644 index 0000000..096163f --- /dev/null +++ b/Canon.Core/GrammarParser/Expression.cs @@ -0,0 +1,78 @@ +namespace Canon.Core.GrammarParser; + +/// +/// An expression in the LR, like 'program_struct -> ~program_head ; program_body.' +/// The '~' is the shift position now. +/// +public class Expression : IEquatable +{ + public required NonTerminator Left { get; init; } + + public required Terminator LookAhead { get; init; } + + public required List Right { get; init; } + + public int Pos { get; set; } + + public bool Equals(Expression? other) + { + if (other is null) + { + return false; + } + + if (Right.Count != other.Right.Count) + { + return false; + } + + for (int i = 0; i < Right.Count; i++) + { + if (Right[i].IsTerminated != other.Right[i].IsTerminated) + { + return false; + } + + if (!Right[i].Equals(other.Right[i])) + { + return false; + } + } + + return Left == other.Left + && LookAhead == other.LookAhead; + } + + public override bool Equals(object? obj) + { + if (obj is not Expression other) + { + return false; + } + + return Equals(other); + } + + public override int GetHashCode() + { + int hash = Left.GetHashCode(); + hash ^= LookAhead.GetHashCode(); + + foreach (TerminatorBase terminator in Right) + { + hash ^= terminator.GetHashCode(); + } + + return hash; + } + + public static bool operator ==(Expression a, Expression b) + { + return a.Equals(b); + } + + public static bool operator !=(Expression a, Expression b) + { + return !a.Equals(b); + } +} diff --git a/Canon.Core/GrammarParser/Terminator.cs b/Canon.Core/GrammarParser/Terminator.cs new file mode 100644 index 0000000..0ff1257 --- /dev/null +++ b/Canon.Core/GrammarParser/Terminator.cs @@ -0,0 +1,137 @@ +using Canon.Core.Enums; + +namespace Canon.Core.GrammarParser; + +public abstract class TerminatorBase +{ + public abstract bool IsTerminated { get; } +} + +/// +/// A terminator in grammar and it always represents a semantic token. +/// +public class Terminator : TerminatorBase, IEquatable +{ + public override bool IsTerminated => true; + + private readonly bool _isKeyword; + + private readonly KeywordType _keywordType; + private readonly DelimiterType _delimiterType; + + public Terminator(KeywordType keywordType) + { + _isKeyword = true; + _keywordType = keywordType; + } + + public Terminator(DelimiterType delimiterType) + { + _isKeyword = false; + _delimiterType = delimiterType; + } + + public override int GetHashCode() + { + if (_isKeyword) + { + return _keywordType.GetHashCode(); + } + else + { + return _delimiterType.GetHashCode(); + } + } + + public bool Equals(Terminator? other) + { + if (other is null) + { + return false; + } + + if (_isKeyword != other._isKeyword) + { + return false; + } + + if (_isKeyword) + { + return _keywordType == other._keywordType; + } + else + { + return _delimiterType == other._delimiterType; + } + } + + public override bool Equals(object? obj) + { + if (obj is not Terminator other) + { + return false; + } + + return Equals(other); + } + + public static bool operator ==(Terminator a, Terminator b) + { + return a.Equals(b); + } + + public static bool operator !=(Terminator a, Terminator b) + { + return !a.Equals(b); + } +} + +/// +/// A non-terminator in grammar like the 'ProgramStruct'. +/// +public class NonTerminator : TerminatorBase, IEquatable +{ + public override bool IsTerminated => false; + + private readonly NonTerminatorType _type; + + public NonTerminator(NonTerminatorType type) + { + _type = type; + } + + public override int GetHashCode() + { + return _type.GetHashCode(); + } + + public bool Equals(NonTerminator? other) + { + if (other is null) + { + return false; + } + + return _type == other._type; + } + + public override bool Equals(object? obj) + { + if (obj is not NonTerminator other) + { + return false; + } + + return Equals(other); + } + + public static bool operator ==(NonTerminator a, NonTerminator b) + { + return a.Equals(b); + } + + public static bool operator !=(NonTerminator a, NonTerminator b) + { + return !a.Equals(b); + } +}