diff --git a/Canon.Core/SemanticParser/PascalType.cs b/Canon.Core/SemanticParser/PascalType.cs index 9edc16b..2e815e2 100644 --- a/Canon.Core/SemanticParser/PascalType.cs +++ b/Canon.Core/SemanticParser/PascalType.cs @@ -52,6 +52,11 @@ public abstract class PascalType : IEquatable throw new InvalidOperationException(); } + if (a == PascalBasicType.Boolean && b == PascalBasicType.Boolean) + { + return PascalBasicType.Boolean; + } + if (a == PascalBasicType.Integer && b == PascalBasicType.Integer) { return PascalBasicType.Integer; @@ -69,6 +74,7 @@ public abstract class PascalType : IEquatable /// 是否为可计算的类型 public static bool IsCalculatable(PascalType pascalType) { - return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real; + return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real + || pascalType == PascalBasicType.Boolean; } } diff --git a/Canon.Core/SemanticParser/TypeCheckVisitor.cs b/Canon.Core/SemanticParser/TypeCheckVisitor.cs index fcbd119..15fb5c9 100644 --- a/Canon.Core/SemanticParser/TypeCheckVisitor.cs +++ b/Canon.Core/SemanticParser/TypeCheckVisitor.cs @@ -496,20 +496,46 @@ public class TypeCheckVisitor(ILogger? logger = null) : Syntax public override void PostVisit(ProcedureCall procedureCall) { base.PostVisit(procedureCall); - // 查看procedureId是否注册 + // 查看当前符号表中procedureId是否注册 + if (!SymbolTable.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedure)) { + // id没有定义 IsError = true; - logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.IdentifierName); + logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue); return; } - // 查看该符号是否为procedure if (procedure.SymbolType is not PascalFunctionType functionType) { - IsError = true; - logger?.LogError("Identifier '{}' is not a call-able.", procedure.SymbolName); - return; + // id不是函数类型,要找父符号表 + if (!SymbolTable.TryGetParent(out SymbolTable? parent)) + { + // 没找到父符号表,说明这个id是非函数变量 + IsError = true; + logger?.LogError("Identifier '{}' is not a call-able.", procedureCall.ProcedureId.LiteralValue); + return; + } + + if (!parent.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedureParent)) + { + // 找到父符号表但没有找到该id,说明这个id没定义 + IsError = true; + logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue); + return; + } + + // 父符号表中找到该id + if (procedureParent.SymbolType is not PascalFunctionType functionTypeParent) + { + // 该符号不是函数类型 + IsError = true; + logger?.LogError("Identifier '{}' is not a call-able.", procedureParent.SymbolName); + return; + } + // 该符号是函数类型,赋给procedure + procedure = procedureParent; + functionType = functionTypeParent; } procedureCall.OnParameterGenerator += (_, e) => diff --git a/Canon.Tests/SemanticTests/TypeCheckVisitorTests.cs b/Canon.Tests/SemanticTests/TypeCheckVisitorTests.cs index c41b035..0f853b2 100644 --- a/Canon.Tests/SemanticTests/TypeCheckVisitorTests.cs +++ b/Canon.Tests/SemanticTests/TypeCheckVisitorTests.cs @@ -426,7 +426,7 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper) end; begin - findMin(a, b, c,error); + findmin(a, b, c,error); (* Procedure call *) end. """; @@ -436,6 +436,32 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper) } + [Fact] + public void RecursionProcedureCallTest() + { + const string program = """ + program main; + var a, b:integer; c:real; + function Test0(var a1:integer; b1:integer; c1:real):integer; + begin + test0(a1,b1,c1+0.5); + end; + function Test1(var a1:integer; b1:integer; c1:real):integer; + begin + test0(1,1,1.0); + end; + + begin + teSt1(a,b,1.02); + test(a, b, c); + end. + """; + + TypeCheckVisitor visitor = CheckType(program); + Assert.True(visitor.IsError); + } + + [Fact] public void ArrayAssignIndexTest() { @@ -506,6 +532,23 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper) CheckType(program); } + [Fact] + public void BooleanOperatorTest() + { + const string program = """ + program main; + var flag, tag : boolean; + error:integer; + begin + tag := flag or tag; + flag := flag and error; + end. + """; + + TypeCheckVisitor visitor = CheckType(program); + Assert.True(visitor.IsError); + } + private TypeCheckVisitor CheckType(string program) { ProgramStruct root = CompilerHelpers.Analyse(program);