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