From ccd18997391f37056352c9353ad048d102c371e4 Mon Sep 17 00:00:00 2001
From: Lan_G <2911328695@qq.com>
Date: Sat, 16 Mar 2024 11:05:38 +0800
Subject: [PATCH] feat: symbol-table & type checker (#14)
Reviewed-on: https://git.rrricardo.top/PostGuard/Canon/pulls/14
Co-authored-by: Lan_G <2911328695@qq.com>
Co-committed-by: Lan_G <2911328695@qq.com>
---
Canon.Core/Enums/SemanticEnums.cs | 8 +
Canon.Core/Exceptions/GrammarException.cs | 2 +-
Canon.Core/SemanticParser/IdentifierType.cs | 178 +++++
Canon.Core/SemanticParser/SemanticBuilder.cs | 731 ++++++++++++++++++
Canon.Core/SemanticParser/SymbolTable.cs | 107 +++
Canon.Core/SemanticParser/SymbolTableEntry.cs | 37 +
Canon.Core/SemanticParser/TypeTable.cs | 66 ++
7 files changed, 1128 insertions(+), 1 deletion(-)
create mode 100644 Canon.Core/SemanticParser/IdentifierType.cs
create mode 100644 Canon.Core/SemanticParser/SemanticBuilder.cs
create mode 100644 Canon.Core/SemanticParser/SymbolTable.cs
create mode 100644 Canon.Core/SemanticParser/SymbolTableEntry.cs
create mode 100644 Canon.Core/SemanticParser/TypeTable.cs
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");
+ }
+ }
+
+}