From 4d325569fac7e7bda996ab3f363d982aa4dbf9e9 Mon Sep 17 00:00:00 2001 From: ichirinko <1621543655@qq.com> Date: Mon, 29 Apr 2024 21:33:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E6=94=B9=E5=AF=B9=E9=80=92?= =?UTF-8?q?=E5=BD=92=E5=87=BD=E6=95=B0=E7=9A=84procedureCall=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=A3=80=E6=9F=A5=EF=BC=8C=E5=9C=A8=E7=88=B6=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7=E8=A1=A8=E4=B8=AD=E5=AF=BB=E6=89=BEid=20(#66)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.rrricardo.top/PostGuard/Canon/pulls/66 Co-authored-by: ichirinko <1621543655@qq.com> Co-committed-by: ichirinko <1621543655@qq.com> --- Canon.Core/SemanticParser/PascalType.cs | 8 +++- Canon.Core/SemanticParser/TypeCheckVisitor.cs | 38 +++++++++++++--- .../SemanticTests/TypeCheckVisitorTests.cs | 45 ++++++++++++++++++- 3 files changed, 83 insertions(+), 8 deletions(-) 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);