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