diff --git a/Canon.Core/Enums/SemanticEnums.cs b/Canon.Core/Enums/SemanticEnums.cs index 6057329..3e3bf7f 100644 --- a/Canon.Core/Enums/SemanticEnums.cs +++ b/Canon.Core/Enums/SemanticEnums.cs @@ -95,3 +95,11 @@ public enum StateType Delimiter, Other } + +public enum BasicIdType +{ + Int, + Real, + Char, + Bool +} diff --git a/Canon.Core/Exceptions/GrammarException.cs b/Canon.Core/Exceptions/GrammarException.cs index 59fa1de..a758331 100644 --- a/Canon.Core/Exceptions/GrammarException.cs +++ b/Canon.Core/Exceptions/GrammarException.cs @@ -1,4 +1,4 @@ -namespace Canon.Core.Exceptions; +namespace Canon.Core.Exceptions; /// /// 语法分析中引发的异常 /// diff --git a/Canon.Core/SemanticParser/IdentifierType.cs b/Canon.Core/SemanticParser/IdentifierType.cs new file mode 100644 index 0000000..1dbe9ae --- /dev/null +++ b/Canon.Core/SemanticParser/IdentifierType.cs @@ -0,0 +1,178 @@ +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/SemanticBuilder.cs b/Canon.Core/SemanticParser/SemanticBuilder.cs new file mode 100644 index 0000000..b82d2ab --- /dev/null +++ b/Canon.Core/SemanticParser/SemanticBuilder.cs @@ -0,0 +1,731 @@ +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/SymbolTable.cs b/Canon.Core/SemanticParser/SymbolTable.cs new file mode 100644 index 0000000..d9f9dcd --- /dev/null +++ b/Canon.Core/SemanticParser/SymbolTable.cs @@ -0,0 +1,107 @@ +using Canon.Core.Exceptions; + +namespace Canon.Core.SemanticParser; +/// +///符号表类 +/// +public class SymbolTable +{ + public Dictionary Entries; + + public TypeTable TypesTable; //当前符号表对应的类型表 + + public SymbolTable? PreTable; //直接外围符号表 + + public SymbolTable() + { + Entries = new Dictionary(); + TypesTable = new TypeTable(); + PreTable = null; + } + + public SymbolTable(SymbolTable preTable) + { + Entries = new Dictionary(); + TypesTable = new TypeTable(); + PreTable = preTable; + } + + /// + /// 向符号表里插入一个表项 + /// + 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)); + } + + + /// + ///检查符号表,看是否有变量重复声明 + /// + /// 查询的id名称 + /// 如果变量重复声明,返回true + public bool Check(string idName) + { + 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)) + { + return true; + } + + throw new SemanticException("identifier "+ idName + " is not defined!"); + } + + /// + /// 通过id名获取id的类型 + /// + /// id名字 + /// id在符号表里的类型 + public IdentifierType GetIdTypeByName(string idName) + { + if (Entries.ContainsKey(idName)) + { + return Entries[idName].Type; + } + if (PreTable is not null && PreTable.Entries.ContainsKey(idName)) + { + return PreTable.Entries[idName].Type; + } + + throw new SemanticException("identifier "+ idName + " is not defined!"); + } + + + + public bool IsConst(string idName) + { + return Find(idName) && Entries[idName].IsConst; + } +} diff --git a/Canon.Core/SemanticParser/SymbolTableEntry.cs b/Canon.Core/SemanticParser/SymbolTableEntry.cs new file mode 100644 index 0000000..0e6f612 --- /dev/null +++ b/Canon.Core/SemanticParser/SymbolTableEntry.cs @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..91520b1 --- /dev/null +++ b/Canon.Core/SemanticParser/TypeTable.cs @@ -0,0 +1,66 @@ +using System.Security; +using Canon.Core.Enums; +using Canon.Core.Exceptions; + +namespace Canon.Core.SemanticParser; +/// +/// 类型表 +/// +public class TypeTable +{ + private Dictionary EntryDict { get; init; } + + public TypeTable() + { + 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)); + } + + + /// + /// 判断类型表里是否已经有该类型 + /// + /// 类型名称 + /// 如果有,返回true + public bool Check(string typeName) + { + return EntryDict.ContainsKey(typeName); + } + + /// + /// 往类型表里添加类型 + /// + /// 类型名称 + /// 类型的类别(一般是记录) + 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"); + } + } + + /// + /// 由类型名获取类型 + /// + 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"); + } + } + +}