diff --git a/Canon.Core/Enums/BasicType.cs b/Canon.Core/Enums/BasicType.cs
new file mode 100644
index 0000000..3352d46
--- /dev/null
+++ b/Canon.Core/Enums/BasicType.cs
@@ -0,0 +1,25 @@
+namespace Canon.Core.Enums;
+
+public enum BasicType
+{
+ ///
+ /// 整数类型
+ ///
+ Integer,
+ ///
+ /// 浮点数类型
+ ///
+ Real,
+ ///
+ /// 布尔类型
+ ///
+ Boolean,
+ ///
+ /// 字符类型
+ ///
+ Character,
+ ///
+ /// 空类型
+ ///
+ Void
+}
diff --git a/Canon.Core/SemanticParser/IdentifierType.cs b/Canon.Core/SemanticParser/IdentifierType.cs
deleted file mode 100644
index 1dbe9ae..0000000
--- a/Canon.Core/SemanticParser/IdentifierType.cs
+++ /dev/null
@@ -1,178 +0,0 @@
-using Canon.Core.Enums;
-
-namespace Canon.Core.SemanticParser;
-
-///
-/// 标识符类型基类
-///
-public abstract class IdentifierType;
-
-public class BasicType : IdentifierType
-{
- public BasicIdType IdType;
-
- public BasicType(BasicIdType basicIdType)
- {
- IdType = basicIdType;
- }
-
- public static bool operator ==(BasicType a, BasicType b)
- {
- return a.IdType == b.IdType;
- }
-
- public static bool operator !=(BasicType a, BasicType b)
- {
- return !(a == b);
- }
-}
-
-public class ArrayType : IdentifierType
-{
- public int Dimension;
-
- public List LimitsList;
-
- public IdentifierType ElementType;
-
- public ArrayType(int dimension, List limitsList, IdentifierType elementType)
- {
- Dimension = dimension;
- LimitsList = limitsList;
- ElementType = elementType;
- }
-
- public static bool operator ==(ArrayType a, ArrayType b)
- {
- if (a.Dimension != b.Dimension || a.ElementType != b.ElementType || a.LimitsList.Count != b.LimitsList.Count)
- {
- return false;
- }
-
- int n = a.LimitsList.Count;
- for (int i = 0; i < n; i++)
- {
- if (a.LimitsList[i] != b.LimitsList[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- public static bool operator !=(ArrayType a, ArrayType b)
- {
- return !(a == b);
- }
-}
-
-public class FuncType : IdentifierType
-{
- public List ParamTypeList;
-
- public IdentifierType ReturnType;
-
- public FuncType(List paramTypeList, IdentifierType returnType)
- {
- ParamTypeList = paramTypeList;
- ReturnType = returnType;
- }
-
-}
-
-public class ProcType : IdentifierType
-{
- public List ParamTypeList;
-
- public ProcType()
- {
- ParamTypeList = new List();
- }
-
- public ProcType(List paramTypeList)
- {
- ParamTypeList = paramTypeList;
- }
-}
-
-public class RecordType : IdentifierType
-{
- public Dictionary MemberDic;
-
- public RecordType()
- {
- MemberDic = new Dictionary();
- }
-
- public static bool operator ==(RecordType a, RecordType b)
- {
- if (a.MemberDic.Count != b.MemberDic.Count)
- {
- return false;
- }
-
- foreach (var k in a.MemberDic.Keys)
- {
- if (!b.MemberDic.ContainsKey(k) || a.MemberDic[k] != b.MemberDic[k])
- {
- return false;
- }
- }
-
- return true;
- }
-
- public static bool operator !=(RecordType a, RecordType b)
- {
- return !(a == b);
- }
-
-}
-
-///
-/// 空类型,用于充当procedure的返回值
-///
-public class NonType : IdentifierType
-{
-
-}
-
-public class Limits
-{
- public uint LowerBound;
-
- public uint UpperBound;
-
- public Limits(uint lowerBound, uint upperBound)
- {
- LowerBound = lowerBound;
- UpperBound = upperBound;
- }
-
- public static bool operator ==(Limits a, Limits b)
- {
- return a.LowerBound == b.LowerBound && a.UpperBound == b.UpperBound;
- }
-
- public static bool operator !=(Limits a, Limits b)
- {
- return !(a == b);
- }
-}
-
-public class Param
-{
- public string Name;
-
- public IdentifierType Type;
-
- public bool IsVar;
-
- public Param(string name, IdentifierType type, bool isVar)
- {
- Name = name;
- Type = type;
- IsVar = isVar;
- }
-}
diff --git a/Canon.Core/SemanticParser/PascalArrayType.cs b/Canon.Core/SemanticParser/PascalArrayType.cs
new file mode 100644
index 0000000..4740761
--- /dev/null
+++ b/Canon.Core/SemanticParser/PascalArrayType.cs
@@ -0,0 +1,39 @@
+namespace Canon.Core.SemanticParser;
+
+public class PascalArrayType(PascalType elementType, int begin, int end) : PascalType
+{
+ public PascalType ElementType { get; } = elementType;
+
+ public int Begin { get; } = begin;
+
+ public int End { get; } = end;
+
+ public override string TypeName => $"{ElementType.TypeName}_{Begin}_{End}";
+
+ public override bool Equals(PascalType? other)
+ {
+ if (other is not PascalArrayType pascalArrayType)
+ {
+ return false;
+ }
+
+ if (ElementType != pascalArrayType.ElementType)
+ {
+ return false;
+ }
+
+ if (Begin != pascalArrayType.Begin || End != pascalArrayType.End)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ return ElementType.GetHashCode()
+ ^ Begin.GetHashCode()
+ ^ End.GetHashCode();
+ }
+}
diff --git a/Canon.Core/SemanticParser/PascalBasicType.cs b/Canon.Core/SemanticParser/PascalBasicType.cs
new file mode 100644
index 0000000..bbe3817
--- /dev/null
+++ b/Canon.Core/SemanticParser/PascalBasicType.cs
@@ -0,0 +1,62 @@
+using Canon.Core.Enums;
+
+namespace Canon.Core.SemanticParser;
+
+///
+/// 基础Pascal类型
+///
+public class PascalBasicType : PascalType
+{
+ ///
+ /// 基础类型
+ ///
+ public BasicType Type { get; }
+
+ public override string TypeName { get; }
+
+ private PascalBasicType(BasicType basicType, string typeName)
+ {
+ Type = basicType;
+ TypeName = typeName;
+ }
+
+ public override bool Equals(PascalType? other)
+ {
+ if (other is not PascalBasicType pascalBasicType)
+ {
+ return false;
+ }
+
+ return Type == pascalBasicType.Type;
+ }
+
+ public override int GetHashCode()
+ {
+ return Type.GetHashCode();
+ }
+
+ ///
+ /// 整数类型的单例对象
+ ///
+ public static PascalType Integer => new PascalBasicType(BasicType.Integer, "integer");
+
+ ///
+ /// 布尔类型的单例对象
+ ///
+ public static PascalType Boolean => new PascalBasicType(BasicType.Boolean, "boolean");
+
+ ///
+ /// 字符类型的单例对象
+ ///
+ public static PascalType Character => new PascalBasicType(BasicType.Character, "char");
+
+ ///
+ /// 浮点数类型的单例对象
+ ///
+ public static PascalType Real => new PascalBasicType(BasicType.Real, "real");
+
+ ///
+ /// 空类型的单例对象
+ ///
+ public static PascalType Void => new PascalBasicType(BasicType.Void, "void");
+}
diff --git a/Canon.Core/SemanticParser/PascalFunctionType.cs b/Canon.Core/SemanticParser/PascalFunctionType.cs
new file mode 100644
index 0000000..1bc9a89
--- /dev/null
+++ b/Canon.Core/SemanticParser/PascalFunctionType.cs
@@ -0,0 +1,61 @@
+using System.Text;
+
+namespace Canon.Core.SemanticParser;
+
+public class PascalFunctionType(List parameters, PascalType returnType) : PascalType
+{
+ public List Parameters { get; } = parameters;
+
+ public PascalType ReturnType { get; } = returnType;
+
+ public override string TypeName
+ {
+ get
+ {
+ StringBuilder builder = new();
+
+ foreach (PascalParameterType parameter in Parameters)
+ {
+ builder.Append(parameter.TypeName).Append('_');
+ }
+
+ builder.Append(ReturnType.TypeName);
+ return builder.ToString();
+ }
+ }
+
+ public override bool Equals(PascalType? other)
+ {
+ if (other is not PascalFunctionType functionType)
+ {
+ return false;
+ }
+
+ if (Parameters.Count != functionType.Parameters.Count || ReturnType != functionType.ReturnType)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < Parameters.Count; i++)
+ {
+ if (Parameters[i] != functionType.Parameters[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int code = ReturnType.GetHashCode();
+
+ foreach (PascalParameterType parameter in Parameters)
+ {
+ code ^= parameter.GetHashCode();
+ }
+
+ return code;
+ }
+}
diff --git a/Canon.Core/SemanticParser/PascalParameterType.cs b/Canon.Core/SemanticParser/PascalParameterType.cs
new file mode 100644
index 0000000..d8fb7ce
--- /dev/null
+++ b/Canon.Core/SemanticParser/PascalParameterType.cs
@@ -0,0 +1,38 @@
+namespace Canon.Core.SemanticParser;
+
+public class PascalParameterType(PascalType parameterType, bool isVar) : PascalType
+{
+ public PascalType ParameterType { get; } = parameterType;
+
+ public bool IsVar { get; } = isVar;
+
+ public override string TypeName
+ {
+ get
+ {
+ if (IsVar)
+ {
+ return $"var_{ParameterType.TypeName}";
+ }
+ else
+ {
+ return ParameterType.TypeName;
+ }
+ }
+ }
+
+ public override bool Equals(PascalType? other)
+ {
+ if (other is not PascalParameterType parameterType)
+ {
+ return false;
+ }
+
+ return ParameterType == parameterType.ParameterType && IsVar == parameterType.IsVar;
+ }
+
+ public override int GetHashCode()
+ {
+ return ParameterType.GetHashCode() ^ IsVar.GetHashCode();
+ }
+}
diff --git a/Canon.Core/SemanticParser/PascalType.cs b/Canon.Core/SemanticParser/PascalType.cs
new file mode 100644
index 0000000..fe81049
--- /dev/null
+++ b/Canon.Core/SemanticParser/PascalType.cs
@@ -0,0 +1,47 @@
+namespace Canon.Core.SemanticParser;
+
+///
+/// Pascal类型基类
+///
+public abstract class PascalType : IEquatable
+{
+ ///
+ /// 类型的名称
+ ///
+ public abstract string TypeName { get; }
+
+ public virtual bool Equals(PascalType? other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ return TypeName == other.TypeName;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (obj is PascalType other)
+ {
+ return Equals(other);
+ }
+
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return TypeName.GetHashCode();
+ }
+
+ public static bool operator ==(PascalType a, PascalType b)
+ {
+ return a.Equals(b);
+ }
+
+ public static bool operator !=(PascalType a, PascalType b)
+ {
+ return !a.Equals(b);
+ }
+}
diff --git a/Canon.Core/SemanticParser/SemanticBuilder.cs b/Canon.Core/SemanticParser/SemanticBuilder.cs
deleted file mode 100644
index b82d2ab..0000000
--- a/Canon.Core/SemanticParser/SemanticBuilder.cs
+++ /dev/null
@@ -1,731 +0,0 @@
-using Canon.Core.Enums;
-using Canon.Core.Exceptions;
-using Canon.Core.GrammarParser;
-using Canon.Core.LexicalParser;
-
-namespace Canon.Core.SemanticParser;
-
-public class SemanticBuilder
-{
- private SymbolTable _curSymbolTable; //当前符号表
-
- private Stack _stack;
-
- public SemanticBuilder()
- {
- _curSymbolTable = new SymbolTable();
- _stack = new Stack();
- }
-
-
- ///
- /// 执行语义分析
- ///
- /// 语法树根节点
- public void Build(SyntaxNode root)
- {
- //新建一个符号表,压入栈
- _stack.Push(_curSymbolTable);
- //开始递归调用,完成构建符号表和类型检查
- SolveProgramStruct(root);
- }
-
-
- private void SolveProgramStruct(SyntaxNode root)
- {
- SolveProgramHead(root.Children[0]);
- SolveProgramBody(root.Children[2]);
- }
-
- private void SolveProgramHead(SyntaxNode root)
- {
- //不做任何处理
- }
-
- private void SolveProgramBody(SyntaxNode root)
- {
- SolveConstDeclarations(root.Children[0]);
- SolveVarDeclarations(root.Children[1]);
- SolveSubprogramDeclarations(root.Children[2]);
- SolveCompoundStatement(root.Children[3]);
- }
-
- private void SolveConstDeclarations(SyntaxNode root)
- {
- if (root.Children.Count > 1)
- {
- SolveConstDeclaration(root.Children[1]);
- }
-
- }
-
- private void SolveConstDeclaration(SyntaxNode root)
- {
- int offset = 0;
- if (!root.Children[0].IsTerminated)
- {
- SolveConstDeclaration(root.Children[0]);
- offset = 2;
- }
-
- var idName = root.Children[offset].GetSemanticToken().LiteralValue;
- _curSymbolTable.AddEntry(idName, SolveConstValue(root.Children[offset+2]), true, false);
- }
-
- private IdentifierType SolveConstValue(SyntaxNode root)
- {
- if (root.Children.Count == 3)
- {
- return new BasicType(BasicIdType.Char);
- }
- else
- {
- var t = ((NumberSemanticToken)root.GetSemanticToken()).NumberType;
- if (t == NumberType.Real)
- {
- return new BasicType(BasicIdType.Real);
- }
- else
- {
- return new BasicType(BasicIdType.Int);
- }
- }
- }
-
- private void SolveVarDeclarations(SyntaxNode root)
- {
- if (root.Children.Count > 1)
- {
- SolveVarDeclaration(root.Children[1]);
- }
- }
-
- private void SolveVarDeclaration(SyntaxNode root)
- {
- int offset = 0;
- if (root.Children.Count > 3)
- {
- SolveVarDeclaration(root.Children[0]);
- offset = 2;
- }
-
- List idList = new List();
- SolveIdList(root.Children[offset], idList); //获取待定义的标识符列表
-
- var type = SolveType(root.Children[offset + 2]); //获取类型
-
- //将符号批量插入符号表
- foreach(var id in idList)
- {
- _curSymbolTable.AddEntry(id, type, false, false);
- }
-
- }
-
- private void SolveIdList(SyntaxNode root, List idList)
- {
- if (root.IsTerminated)
- {
- var word = root.GetSemanticToken().LiteralValue;
- if (word != ",")
- {
- idList.Add(word);
- }
- }
-
- foreach (var child in root.Children)
- {
- SolveIdList(child, idList);
- }
- }
-
- private IdentifierType SolveType(SyntaxNode root)
- {
- string typeName = root.Children[0].Children[0].GetSemanticToken().LiteralValue;
- //基本类型或记录类型
- if (root.Children.Count == 1)
- {
- //逐层向外检查类型是否在类型表中
- var cur = _curSymbolTable;
- while (cur != null && !cur.TypesTable.Check(typeName))
- {
- cur = cur.PreTable;
- }
-
- if (cur != null)
- {
- return cur.TypesTable.GetTypeByName(typeName);
- }
-
- throw new SemanticException(typeName + " is an undefined type!");
- }
-
-
- //数组类型
- var limitList = new List();
- SolvePeriod(root.Children[2], limitList);
- return new ArrayType(limitList.Count, limitList, SolveType(root.Children[5]));
- }
-
- private void SolvePeriod(SyntaxNode root, List limitsList)
- {
- int offset = 0;
-
- if (!root.Children[0].IsTerminated)
- {
- SolvePeriod(root.Children[0], limitsList); //递归获取子节点的界限列表
- offset = 2;
- }
-
- //token1和2对应数组当前维度的上下界
- var token1 = (NumberSemanticToken)root.Children[offset].GetSemanticToken();
- var t1 = token1.NumberType;
- var token2 = (NumberSemanticToken)root.Children[offset + 3].GetSemanticToken();
- var t2 = token2.NumberType;
-
- //检查数组上下界定义是否合法
- if (t1 == NumberType.Integer && t2 == NumberType.Integer)
- {
- int lower = int.Parse(token1.LiteralValue);
- int upper = int.Parse(token2.LiteralValue);
- if (upper >= lower)
- {
- if (lower >= 0)
- {
- limitsList.Add(new Limits((uint)lower, (uint)upper));
- return;
- }
-
- throw new SemanticException("Array's bounds must be nonnegative!");
- }
-
- throw new SemanticException("Array's upper bound must greater than low bound!");
- }
-
- throw new SemanticException("Array's bounds must be integer!");
- }
-
- private void SolveSubprogramDeclarations(SyntaxNode root)
- {
- if (root.Children.Count > 1)
- {
- SolveSubprogramDeclarations(root.Children[0]);
- SolveSubprogram(root.Children[1]);
- //处理完一个子过程/函数,将对应符号表出栈,当前符号表更新为新栈顶符号表
- _stack.Pop();
- _curSymbolTable = _stack.Peek();
- }
-
- }
-
- private void SolveSubprogram(SyntaxNode root)
- {
- SolveSubprogramHead(root.Children[0]);
- SolveSubprogramBody(root.Children[2]);
- }
-
- private void SolveSubprogramHead(SyntaxNode root)
- {
- //获取参数列表信息
- List paramList = new List();
- SolveFormalParameter(root.Children[2], paramList);
-
- //区分procedure和function
- IdentifierType identifierType;
- if (root.Children.Count == 3)
- {
- identifierType = new ProcType(paramList);
-
- }
- else
- {
- var type = SolveType(root.Children[4]); //获取函数返回值
- identifierType = new FuncType(paramList, type);
- }
-
- //创建子符号表
- SymbolTable subTable = new SymbolTable(_curSymbolTable);
-
- //将参数列表参数拷贝一份到子符号表
- foreach (var param in paramList)
- {
- subTable.AddEntry(param.Name, param.Type, false, param.IsVar);
- }
-
- //将proc/func头定义写入当前符号表
- _curSymbolTable.AddEntry(root.Children[1].GetSemanticToken().LiteralValue, identifierType, subTable);
-
- //子符号表入栈
- _stack.Push(subTable);
- //更新当前符号表为子符号表
- _curSymbolTable = subTable;
- }
-
- private void SolveFormalParameter(SyntaxNode root, List paramList)
- {
- if (root.Children.Count > 1)
- {
- SolveParameterList(root.Children[1], paramList);
- }
- }
-
- private void SolveParameterList(SyntaxNode root, List paramList)
- {
- int offset = 0;
- if (root.Children.Count > 1)
- {
- SolveParameterList(root, paramList);
- offset = 2;
- }
-
- SolveParameter(root.Children[offset], paramList);
- }
-
- private void SolveParameter(SyntaxNode root, List paramList)
- {
- bool isVarParam = false;
- SyntaxNode node = root.Children[0];
- if (node.GetNonTerminatorType() == NonTerminatorType.VarParameter)
- {
- isVarParam = true;
- node = node.Children[1];
- }
-
- List list = new List();
- SolveIdList(node.Children[0], list);
- var type = SolveType(node.Children[2]);
-
- foreach (var idName in list)
- {
- paramList.Add(new Param(idName, type, isVarParam));
- }
- }
-
-
- private void SolveSubprogramBody(SyntaxNode root)
- {
- SolveConstDeclarations(root.Children[0]);
- SolveVarDeclarations(root.Children[1]);
- SolveCompoundStatement(root.Children[2]);
- }
-
- private void SolveCompoundStatement(SyntaxNode root)
- {
- SolveStatementList(root.Children[1]);
- }
-
- private void SolveStatementList(SyntaxNode root)
- {
- int offset = 0;
- if (root.Children.Count > 1)
- {
- SolveStatementList(root.Children[0]);
- offset = 2;
- }
-
- SolveStatement(root.Children[offset]);
- }
-
- private void SolveStatement(SyntaxNode root)
- {
- var node = root.Children[0];
- if (node.IsTerminated)
- {
- //通过子节点个数判断用的statement的哪个产生式
- int childCount = root.Children.Count;
- switch (childCount)
- {
- case 3:
- CheckFuncAssign(root);
- break;
- case 5:
- SolveIf(root);
- break;
- case 8:
- CheckForLoop(root);
- break;
- default:
- throw new SemanticException("Semantic analysis failed and an illegal node was detected");
- }
- }
- else
- {
- var nonTerminatorType = node.GetNonTerminatorType();
- switch (nonTerminatorType)
- {
- case NonTerminatorType.Variable:
- SolveVariableAssign(root);
- break;
- case NonTerminatorType.ProcedureCall:
- SolveCall(node, false);
- break;
- case NonTerminatorType.CompoundStatement:
- SolveCompoundStatement(node);
- break;
- default:
- throw new SemanticException("Semantic analysis failed and an illegal node was detected");
- }
- }
- }
-
- ///
- /// 处理表达式
- ///
- ///
- /// 表达式类型
- private IdentifierType SolveExpression(SyntaxNode root)
- {
- if (root.Children.Count == 1)
- {
- return SolveSimpleExpression(root.Children[0]);
- }
-
- var type1 = SolveSimpleExpression(root.Children[0]);
- var type2 = SolveSimpleExpression(root.Children[2]);
-
- return CheckRelationOperation(type1, type2);
- }
-
- private IdentifierType SolveSimpleExpression(SyntaxNode root)
- {
- if (root.Children.Count == 1)
- {
- return SolveTerm(root.Children[0]);
- }
-
- var type1 = SolveSimpleExpression(root.Children[0]);
- var type2 = SolveTerm(root.Children[2]);
-
- return CheckAddOperation(type1, type2, root.Children[1].Children[0].GetSemanticToken());
- }
-
- private IdentifierType SolveTerm(SyntaxNode root)
- {
- if (root.Children.Count == 1)
- {
- return SolveFactor(root.Children[0]);
- }
-
- var type1 = SolveTerm(root.Children[0]);
- var type2 = SolveFactor(root.Children[2]);
-
- return CheckMultiplyOperation(type1, type2, root.Children[1].Children[0].GetSemanticToken());
- }
-
- private IdentifierType SolveFactor(SyntaxNode root)
- {
- if (root.Children.Count == 1)
- {
- if (root.Children[0].IsTerminated)
- {
- var numberSemanticToken = (NumberSemanticToken)root.Children[0].GetSemanticToken();
- if (numberSemanticToken.NumberType == NumberType.Real)
- {
- return _curSymbolTable.TypesTable.GetTypeByName("real");
- }
-
- return _curSymbolTable.TypesTable.GetTypeByName("integer");
- }
-
- return SolveVariable(root.Children[0]);
- }
-
- //处理 Factor -> (expression)
- if (root.Children.Count == 3)
- {
- return SolveExpression(root.Children[1]);
- }
-
- //函数掉用
- if (root.Children.Count == 4)
- {
- return SolveCall(root, true);
- }
-
- //处理 Factor -> not Factor
- if (root.Children[0].GetSemanticToken() == new Terminator(KeywordType.Not))
- {
- var type = SolveFactor(root.Children[1]);
- if (type == _curSymbolTable.TypesTable.GetTypeByName("boolean"))
- {
- return type;
- }
-
- throw new SemanticException("NOT can only be used for Boolean expressions");
- }
-
- //处理数字取负
- var type1 = SolveFactor(root.Children[1]);
- if (type1 == _curSymbolTable.TypesTable.GetTypeByName("integer") ||
- type1 == _curSymbolTable.TypesTable.GetTypeByName("real"))
- {
- return type1;
- }
-
- throw new SemanticException("minus can only be used on integer or real");
- }
-
- private void SolveIf(SyntaxNode root)
- {
- var boolType = _curSymbolTable.TypesTable.GetTypeByName("boolean");
- if (SolveExpression(root.Children[0]) != boolType)
- {
- throw new SemanticException("The conditional expression of the if statement must be of type Boolean");
- }
-
- SolveStatement(root.Children[3]);
- SolveElsePart(root.Children[4]);
- }
-
- private void SolveElsePart(SyntaxNode root)
- {
- if (root.Children.Count > 1)
- {
- SolveStatement(root.Children[1]);
- }
- }
-
- private void CheckForLoop(SyntaxNode root)
- {
- var intType = _curSymbolTable.TypesTable.GetTypeByName("integer");
- string idName = root.Children[1].GetSemanticToken().LiteralValue;
- if (_curSymbolTable.Find(idName) && _curSymbolTable.GetIdTypeByName(idName) == intType)
- {
- if (SolveExpression(root.Children[3]) == intType && SolveExpression(root.Children[5]) == intType)
- {
- SolveStatement(root.Children[7]);
- }
- else
- {
- throw new SemanticException("The upper and lower bounds of the loop variable in the for loop" +
- " must be set to integer");
- }
- }
- else
- {
- throw new SemanticException("The loop variable in the for loop must be integer");
- }
- }
-
- private void SolveVariableAssign(SyntaxNode root)
- {
- var varType = SolveVariable(root.Children[0]);
- var expType = SolveExpression(root.Children[2]);
- CheckAssign(varType, expType);
-
- //常量不允许被重复赋值
- var idName = root.Children[0].GetSemanticToken().LiteralValue;
- if (_curSymbolTable.IsConst(idName))
- {
- throw new SemanticException("Constants defined as const are not allowed to be assigned repeatedly");
- }
- }
-
- private IdentifierType SolveVariable(SyntaxNode root)
- {
- var idName = root.Children[0].GetSemanticToken().LiteralValue;
- var idType = _curSymbolTable.GetIdTypeByName(idName);
- if (idType is BasicType)
- {
- if (root.Children[1].Children.Count == 1)
- {
- return idType;
- }
-
- throw new SemanticException("The reference to variable "+ idName+ " is illegal");
- }
-
- //暂时只考虑数组类型
- List typeList = new List();
- SolveExpressionList(root.Children[1].Children[1], typeList);
-
- int dimension = ((ArrayType)idType).Dimension;
- //数组引用维数一致
- if (typeList.Count == dimension)
- {
- //每个维度的表达式类型都是int
- var IntType = _curSymbolTable.TypesTable.GetTypeByName("integer");
- foreach (var t in typeList)
- {
- if (t != IntType)
- {
- throw new SemanticException("Array's index must be integer!");
- }
- }
-
- return ((ArrayType)idType).ElementType;
- }
-
- throw new SemanticException("The reference to array " + idName + " requires " + dimension + " subscripts");
- }
-
- private void SolveExpressionList(SyntaxNode root, List typeList)
- {
- int offset = 0;
- if (root.Children.Count > 1)
- {
- SolveExpressionList(root.Children[0], typeList);
- offset = 2;
- }
-
- typeList.Add(SolveExpression(root.Children[offset]));
- }
-
- private IdentifierType SolveCall(SyntaxNode root, bool isFunc)
- {
- var idName = root.Children[0].GetSemanticToken().LiteralValue;
- IdentifierType idType = _curSymbolTable.GetIdTypeByName(idName);
- //获取调用表达式的类型列表
- List typeList = new List();
- SolveExpressionList(root.Children[2], typeList);
- //将调用类型列表和定义参数列表的类型一一比对
- var paramList = isFunc ? ((FuncType)idType).ParamTypeList : ((ProcType)idType).ParamTypeList;
- if (paramList.Count == typeList.Count)
- {
- int n = paramList.Count;
- for (int i = 0; i < n; i++) {
- if (paramList[i].Type != typeList[i])
- {
- throw new SemanticException("The parameter types are inconsistent");
- }
- }
-
- return isFunc ? ((FuncType)idType).ReturnType : new NonType();
- }
-
- throw new SemanticException("The number of parameters of procedure is inconsistent");
- }
-
- private void CheckFuncAssign(SyntaxNode root)
- {
- if (_curSymbolTable.PreTable is null)
- {
- throw new SemanticException("Not allowed to assign a value to a function name in the main program");
- }
- //获取函数返回值类型
- var idType =
- ((FuncType)_curSymbolTable.PreTable.GetIdTypeByName(root.Children[0].GetSemanticToken().LiteralValue)).ReturnType;
- //获取右侧表达式类型
- var expressionType = SolveExpression(root.Children[2]);
- //对赋值进行类型检查
- CheckAssign(idType, expressionType);
- }
-
- ///
- /// 检查赋值语句左右部分类型是否相容
- ///
- /// 赋值号左边类型(若为函数,则取返回值)
- /// 赋值号右边类型
- private void CheckAssign(IdentifierType leftType, IdentifierType rightType)
- {
- if (leftType == rightType)
- {
- return;
- }
-
- var intType = _curSymbolTable.TypesTable.GetTypeByName("integer");
- var realType = _curSymbolTable.TypesTable.GetTypeByName("real");
-
- if (leftType == realType && rightType == intType) //int可以赋值给real
- {
- return;
- }
-
- throw new SemanticException("Incompatible types in assign operation");
- }
-
- ///
- /// 检查关系操作(比大小)的操作数类型
- ///
- /// 左边符号类型
- /// 右边符号类型
- /// 成功则返回boolean类型
- private IdentifierType CheckRelationOperation(IdentifierType leftType, IdentifierType rightType)
- {
- var intType = _curSymbolTable.TypesTable.GetTypeByName("integer");
- var realType = _curSymbolTable.TypesTable.GetTypeByName("real");
- var boolType = _curSymbolTable.TypesTable.GetTypeByName("boolean");
-
- //左右为相等的基本类型或 一个int和一个real
- if (leftType == rightType && leftType is BasicType ||
- leftType == intType && rightType == realType ||
- leftType == realType && rightType == intType)
- {
- return boolType;
- }
-
- throw new SemanticException("Incompatible types in relation operations");
- }
-
-
- private IdentifierType CheckAddOperation(IdentifierType leftType, IdentifierType rightType, SemanticToken semanticToken)
- {
- // or操作两边必为boolean
- var boolType = _curSymbolTable.TypesTable.GetTypeByName("boolean");
- if (semanticToken == new Terminator(KeywordType.Or))
- {
- if (leftType == boolType && rightType == boolType)
- {
- return boolType;
- }
-
- throw new SemanticException("Incompatible types in add operation \"or\"");
- }
-
- var intType = _curSymbolTable.TypesTable.GetTypeByName("integer");
- var realType = _curSymbolTable.TypesTable.GetTypeByName("real");
-
- //左右为相等的基本类型但不为boolean
- if (leftType == rightType && leftType is BasicType && leftType != boolType)
- {
- return leftType;
- }
- //int和real可兼容
- if (leftType == intType && rightType == realType || leftType == realType && rightType == intType)
- {
- return realType;
- }
-
- throw new SemanticException("Incompatible types in add operations");
- }
-
- private IdentifierType CheckMultiplyOperation(IdentifierType leftType, IdentifierType rightType, SemanticToken semanticToken)
- {
- // and操作两边必为boolean
- var boolType = _curSymbolTable.TypesTable.GetTypeByName("boolean");
- if (semanticToken == new Terminator(KeywordType.And))
- {
- if (leftType == boolType && rightType == boolType)
- {
- return boolType;
- }
-
- throw new SemanticException("Incompatible types in multiply operation \"and\"");
- }
-
- // div和mod操作数必为int
- var intType = _curSymbolTable.TypesTable.GetTypeByName("integer");
- if (semanticToken == new Terminator(KeywordType.Mod) || semanticToken == new Terminator(KeywordType.Divide))
- {
- if (leftType == intType && rightType == intType)
- {
- return intType;
- }
- throw new SemanticException("Incompatible types in multiply operation \"mod/div\"");
- }
-
- //都是int或都是real
- var realType = _curSymbolTable.TypesTable.GetTypeByName("real");
- if (leftType == intType && rightType == intType || leftType == realType && rightType == realType)
- {
- return leftType;
- }
- //一个是int,另一个real
- if (leftType == intType && rightType == realType || leftType == realType && rightType == intType)
- {
- return realType;
- }
-
- throw new SemanticException("Incompatible types in multiply operations");
- }
-}
diff --git a/Canon.Core/SemanticParser/Symbol.cs b/Canon.Core/SemanticParser/Symbol.cs
new file mode 100644
index 0000000..7b8e212
--- /dev/null
+++ b/Canon.Core/SemanticParser/Symbol.cs
@@ -0,0 +1,58 @@
+namespace Canon.Core.SemanticParser;
+
+///
+/// 符号表表项类
+///
+public class Symbol : IEquatable
+{
+ ///
+ /// 符号的名称
+ ///
+ public required string SymbolName { get; init; }
+
+ ///
+ /// 符号的类型
+ ///
+ public required PascalType SymbolType { get; init; }
+
+ ///
+ /// 是否为常量
+ ///
+ public bool Const { get; init; }
+
+ ///
+ /// 是否为引用变量
+ ///
+ public bool Reference { get; init; }
+
+ public bool Equals(Symbol? other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ return SymbolName == other.SymbolName
+ && SymbolType == other.SymbolType
+ && Const == other.Const
+ && Reference == other.Reference;
+ }
+
+ public override int GetHashCode()
+ {
+ return SymbolName.GetHashCode();
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (obj is not Symbol other)
+ {
+ return false;
+ }
+
+ return Equals(other);
+ }
+}
+
+
+
diff --git a/Canon.Core/SemanticParser/SymbolTable.cs b/Canon.Core/SemanticParser/SymbolTable.cs
index d9f9dcd..04fbc53 100644
--- a/Canon.Core/SemanticParser/SymbolTable.cs
+++ b/Canon.Core/SemanticParser/SymbolTable.cs
@@ -1,107 +1,109 @@
-using Canon.Core.Exceptions;
+using System.Diagnostics.CodeAnalysis;
namespace Canon.Core.SemanticParser;
+
///
///符号表类
///
public class SymbolTable
{
- public Dictionary Entries;
+ ///
+ /// 符号表
+ ///
+ private readonly Dictionary _symbols = [];
- public TypeTable TypesTable; //当前符号表对应的类型表
+ ///
+ /// 类型表
+ ///
+ private readonly TypeTable _typeTable = new();
- public SymbolTable? PreTable; //直接外围符号表
+ ///
+ /// 父符号表
+ ///
+ private readonly SymbolTable? _parent;
- public SymbolTable()
+ ///
+ /// 获得当前符号表的所有父符号表
+ ///
+ public IEnumerable ParentTables => GetParents();
+
+ public SymbolTable() {}
+
+ private SymbolTable(SymbolTable parent)
{
- Entries = new Dictionary();
- TypesTable = new TypeTable();
- PreTable = null;
+ _parent = parent;
}
- public SymbolTable(SymbolTable preTable)
+ public SymbolTable CreateChildTable()
{
- Entries = new Dictionary();
- TypesTable = new TypeTable();
- PreTable = preTable;
+ return new SymbolTable(this);
}
///
- /// 向符号表里插入一个表项
+ /// 尝试向符号表中添加符号
///
- public void AddEntry(string idName, IdentifierType type, bool isConst, bool isVarParam)
- {
- if (Check(idName))
- {
- throw new SemanticException("failed to insert to SymbolTable! " + idName + " is defined repeatedly");
- }
-
- Entries.Add(idName, new SymbolTableEntry(idName, type, isConst, isVarParam));
- }
-
- public void AddEntry(string idName, IdentifierType type, SymbolTable subTable)
- {
- if (Check(idName))
- {
- throw new SemanticException("failed to insert to SymbolTable! " + idName + " is defined repeatedly");
- }
-
- Entries.Add(idName, new SymbolTableEntry(idName, type, subTable));
- }
-
+ /// 欲添加的符号
+ /// 是否添加成功
+ public bool TryAddSymbol(Symbol symbol) => _symbols.TryAdd(symbol.SymbolName, symbol);
///
- ///检查符号表,看是否有变量重复声明
+ /// 尝试从符号表极其父符号表查找符号
///
- /// 查询的id名称
- /// 如果变量重复声明,返回true
- public bool Check(string idName)
+ /// 需要查找的符号名称
+ /// 查找到的符号
+ /// 是否查找到符号
+ public bool TryGetSymbol(string name, [NotNullWhen(true)] out Symbol? symbol)
{
- return Entries.ContainsKey(idName);
- }
-
- ///
- /// 在符号表里查找,看当前引用变量是否声明
- ///
- /// 查询的id名称
- /// 如果有定义,返回true
- public bool Find(string idName)
- {
- if (Entries.ContainsKey(idName))
- {
- return true;
- }
- if (PreTable is not null && PreTable.Entries.ContainsKey(idName))
+ if (_symbols.TryGetValue(name, out symbol))
{
return true;
}
- throw new SemanticException("identifier "+ idName + " is not defined!");
+ foreach (SymbolTable table in ParentTables)
+ {
+ if (table._symbols.TryGetValue(name, out symbol))
+ {
+ return true;
+ }
+ }
+
+ symbol = null;
+ return false;
}
///
- /// 通过id名获取id的类型
+ /// 从符号表极其父表的类型表中查找类型
///
- /// id名字
- /// id在符号表里的类型
- public IdentifierType GetIdTypeByName(string idName)
+ /// 欲查找的类型名称
+ /// 查找到的类型
+ /// 是否查找到类型
+ public bool TryGetType(string typeName, [NotNullWhen(true)] out PascalType? type)
{
- if (Entries.ContainsKey(idName))
+ if (_typeTable.TryGetType(typeName, out type))
{
- return Entries[idName].Type;
- }
- if (PreTable is not null && PreTable.Entries.ContainsKey(idName))
- {
- return PreTable.Entries[idName].Type;
+ return true;
}
- throw new SemanticException("identifier "+ idName + " is not defined!");
+ foreach (SymbolTable parent in ParentTables)
+ {
+ if (parent._typeTable.TryGetType(typeName, out type))
+ {
+ return true;
+ }
+ }
+
+ type = null;
+ return false;
}
-
-
- public bool IsConst(string idName)
+ private IEnumerable GetParents()
{
- return Find(idName) && Entries[idName].IsConst;
+ SymbolTable? now = _parent;
+
+ while (now is not null)
+ {
+ yield return now;
+ now = now._parent;
+ }
}
}
diff --git a/Canon.Core/SemanticParser/SymbolTableEntry.cs b/Canon.Core/SemanticParser/SymbolTableEntry.cs
deleted file mode 100644
index 0e6f612..0000000
--- a/Canon.Core/SemanticParser/SymbolTableEntry.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace Canon.Core.SemanticParser;
-///
-/// 符号表表项类
-///
-public class SymbolTableEntry
-{
- public string Name;
-
- public IdentifierType Type;
-
- public bool IsConst; //是否为常量
-
- public bool IsVarParam; //是否为引用变量
-
- public SymbolTable? SubTable; //当前表项的子表
-
- public SymbolTableEntry(string name, IdentifierType type, bool isConst, bool isVarParam)
- {
- Name = name;
- Type = type;
- IsConst = isConst;
- IsVarParam = isVarParam;
- }
-
- public SymbolTableEntry(string name, IdentifierType type, SymbolTable subTable)
- {
- Name = name;
- Type = type;
- IsConst = false;
- IsVarParam = false;
- SubTable = subTable;
- }
-}
-
-
-
-
diff --git a/Canon.Core/SemanticParser/TypeTable.cs b/Canon.Core/SemanticParser/TypeTable.cs
index 91520b1..6b82f0e 100644
--- a/Canon.Core/SemanticParser/TypeTable.cs
+++ b/Canon.Core/SemanticParser/TypeTable.cs
@@ -1,66 +1,37 @@
-using System.Security;
-using Canon.Core.Enums;
+using System.Diagnostics.CodeAnalysis;
+using System.Security;
using Canon.Core.Exceptions;
namespace Canon.Core.SemanticParser;
+
///
/// 类型表
///
public class TypeTable
{
- private Dictionary EntryDict { get; init; }
-
- public TypeTable()
+ private readonly Dictionary _types = new()
{
- EntryDict = new Dictionary();
- //加入4种基本类型
- EntryDict.Add("integer", new BasicType(BasicIdType.Int));
- EntryDict.Add("real", new BasicType(BasicIdType.Real));
- EntryDict.Add("char", new BasicType(BasicIdType.Char));
- EntryDict.Add("boolean", new BasicType(BasicIdType.Bool));
- }
-
+ { PascalBasicType.Integer.TypeName, PascalBasicType.Integer },
+ { PascalBasicType.Boolean.TypeName, PascalBasicType.Boolean },
+ { PascalBasicType.Character.TypeName, PascalBasicType.Character },
+ { PascalBasicType.Real.TypeName, PascalBasicType.Real }
+ };
///
- /// 判断类型表里是否已经有该类型
+ /// 根据类型名称查找类型表
///
- /// 类型名称
- /// 如果有,返回true
- public bool Check(string typeName)
+ /// 想要查找的类型名称
+ /// 查找到的类型
+ /// 是否查找到类型
+ public bool TryGetType(string typeName, [NotNullWhen(true)] out PascalType? type)
{
- return EntryDict.ContainsKey(typeName);
- }
+ if (!_types.ContainsKey(typeName))
+ {
+ type = null;
+ return false;
+ }
- ///
- /// 往类型表里添加类型
- ///
- /// 类型名称
- /// 类型的类别(一般是记录)
- public void AddEntry(string typeName, IdentifierType identifierType)
- {
- if (!Check(typeName))
- {
- EntryDict.Add(typeName, identifierType);
- }
- else
- {
- throw new SemanticException("Failed to add to TypeTable! Types were repeatedly defined");
- }
+ type = _types[typeName];
+ return true;
}
-
- ///
- /// 由类型名获取类型
- ///
- public IdentifierType GetTypeByName(string typeName)
- {
- if (Check(typeName))
- {
- return EntryDict[typeName];
- }
- else
- {
- throw new SecurityException("Failed to get type from typeTable! Type is not existed");
- }
- }
-
}
diff --git a/Canon.Tests/SemanticTests/PascalTypeTests.cs b/Canon.Tests/SemanticTests/PascalTypeTests.cs
new file mode 100644
index 0000000..ff07e64
--- /dev/null
+++ b/Canon.Tests/SemanticTests/PascalTypeTests.cs
@@ -0,0 +1,50 @@
+using Canon.Core.SemanticParser;
+
+namespace Canon.Tests.SemanticTests;
+
+public class PascalTypeTests
+{
+ [Fact]
+ public void PascalBasicTypeTests()
+ {
+ PascalType integer = PascalBasicType.Integer;
+ PascalType boolean = PascalBasicType.Boolean;
+ PascalType character = PascalBasicType.Character;
+ PascalType real = PascalBasicType.Real;
+ PascalType voidType = PascalBasicType.Void;
+
+ Assert.Equal(integer, PascalBasicType.Integer);
+ Assert.Equal(boolean, PascalBasicType.Boolean);
+
+ Assert.NotEqual(integer, character);
+ Assert.NotEqual(boolean, real);
+ Assert.NotEqual(character, voidType);
+ }
+
+ [Fact]
+ public void PascalArrayTypeTests()
+ {
+ PascalType array1 = new PascalArrayType(PascalBasicType.Integer, 0, 10);
+ PascalType array2 = new PascalArrayType(PascalBasicType.Integer, 0, 10);
+
+ Assert.Equal(array1, array2);
+
+ PascalType array3 = new PascalArrayType(PascalBasicType.Integer, -9, -3);
+ Assert.NotEqual(array1, array3);
+ }
+
+ [Fact]
+ public void PascalFunctionTypeTests()
+ {
+ PascalType function1 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Integer, false)],
+ PascalBasicType.Void);
+ PascalType function2 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Integer, false)],
+ PascalBasicType.Void);
+
+ Assert.Equal(function1, function2);
+
+ PascalType function3 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Real, true)],
+ PascalBasicType.Integer);
+ Assert.NotEqual(function1, function3);
+ }
+}
diff --git a/Canon.Tests/SemanticTests/SymbolTableTests.cs b/Canon.Tests/SemanticTests/SymbolTableTests.cs
new file mode 100644
index 0000000..d2f59d0
--- /dev/null
+++ b/Canon.Tests/SemanticTests/SymbolTableTests.cs
@@ -0,0 +1,66 @@
+using Canon.Core.SemanticParser;
+
+namespace Canon.Tests.SemanticTests;
+
+public class SymbolTableTests
+{
+ [Fact]
+ public void BasicTypeTest()
+ {
+ SymbolTable table = new();
+
+ Assert.True(table.TryGetType("integer", out PascalType? integer));
+ Assert.Equal(PascalBasicType.Integer, integer);
+ Assert.True(table.TryGetType("real", out PascalType? real));
+ Assert.Equal(PascalBasicType.Real, real);
+ Assert.True(table.TryGetType("boolean", out PascalType? boolean));
+ Assert.Equal(PascalBasicType.Boolean, boolean);
+ Assert.True(table.TryGetType("char", out PascalType? character));
+ Assert.Equal(PascalBasicType.Character, character);
+ }
+
+ [Fact]
+ public void SingleTableInsertAndFindTest()
+ {
+ SymbolTable table = new();
+
+ Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Integer }));
+ Assert.True(table.TryAddSymbol(new Symbol
+ {
+ SymbolName = "temperature", SymbolType = PascalBasicType.Real, Const = true
+ }));
+
+ Assert.True(table.TryGetSymbol("a", out Symbol? a));
+ Assert.Equal(PascalBasicType.Integer, a.SymbolType);
+
+ Assert.False(table.TryGetSymbol("notExist", out a));
+ }
+
+ [Fact]
+ public void NestedTableInsertAndFindTest()
+ {
+ SymbolTable table = new();
+
+ Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Integer }));
+ Assert.True(table.TryAddSymbol(new Symbol
+ {
+ SymbolName = "temperature", SymbolType = PascalBasicType.Real, Const = true
+ }));
+
+ SymbolTable child = table.CreateChildTable();
+
+ Assert.True(child.TryAddSymbol(new Symbol{SymbolName = "a", SymbolType = PascalBasicType.Real}));
+ Assert.True(child.TryAddSymbol(new Symbol
+ {
+ SymbolName = "level2", SymbolType = PascalBasicType.Boolean, Reference = true
+ }));
+
+ Assert.True(child.TryGetSymbol("a", out Symbol? a));
+ Assert.Equal(PascalBasicType.Real, a.SymbolType);
+ Assert.True(table.TryGetSymbol("a", out a));
+ Assert.Equal(PascalBasicType.Integer, a.SymbolType);
+
+ Assert.True(table.TryGetSymbol("temperature", out Symbol? temp));
+ Assert.Equal(PascalBasicType.Real, temp.SymbolType);
+ }
+}