fix:修改对递归函数的procedureCall类型检查,在父符号表中寻找id (#66)

Reviewed-on: PostGuard/Canon#66
Co-authored-by: ichirinko <1621543655@qq.com>
Co-committed-by: ichirinko <1621543655@qq.com>
This commit is contained in:
ichirinko 2024-04-29 21:33:09 +08:00 committed by jackfiled
parent 03852ed2bf
commit 4d325569fa
3 changed files with 83 additions and 8 deletions

View File

@ -52,6 +52,11 @@ public abstract class PascalType : IEquatable<PascalType>
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
if (a == PascalBasicType.Boolean && b == PascalBasicType.Boolean)
{
return PascalBasicType.Boolean;
}
if (a == PascalBasicType.Integer && b == PascalBasicType.Integer) if (a == PascalBasicType.Integer && b == PascalBasicType.Integer)
{ {
return PascalBasicType.Integer; return PascalBasicType.Integer;
@ -69,6 +74,7 @@ public abstract class PascalType : IEquatable<PascalType>
/// <returns>是否为可计算的类型</returns> /// <returns>是否为可计算的类型</returns>
public static bool IsCalculatable(PascalType pascalType) public static bool IsCalculatable(PascalType pascalType)
{ {
return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real; return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real
|| pascalType == PascalBasicType.Boolean;
} }
} }

View File

@ -496,20 +496,46 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
public override void PostVisit(ProcedureCall procedureCall) public override void PostVisit(ProcedureCall procedureCall)
{ {
base.PostVisit(procedureCall); base.PostVisit(procedureCall);
// 查看procedureId是否注册 // 查看当前符号表中procedureId是否注册
if (!SymbolTable.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedure)) if (!SymbolTable.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedure))
{ {
// id没有定义
IsError = true; IsError = true;
logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.IdentifierName); logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.LiteralValue);
return; return;
} }
// 查看该符号是否为procedure
if (procedure.SymbolType is not PascalFunctionType functionType) if (procedure.SymbolType is not PascalFunctionType functionType)
{ {
IsError = true; // id不是函数类型,要找父符号表
logger?.LogError("Identifier '{}' is not a call-able.", procedure.SymbolName); if (!SymbolTable.TryGetParent(out SymbolTable? parent))
return; {
// 没找到父符号表,说明这个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) => procedureCall.OnParameterGenerator += (_, e) =>

View File

@ -426,7 +426,7 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
end; end;
begin begin
findMin(a, b, c,error); findmin(a, b, c,error);
(* Procedure call *) (* Procedure call *)
end. 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] [Fact]
public void ArrayAssignIndexTest() public void ArrayAssignIndexTest()
{ {
@ -506,6 +532,23 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
CheckType(program); 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) private TypeCheckVisitor CheckType(string program)
{ {
ProgramStruct root = CompilerHelpers.Analyse(program); ProgramStruct root = CompilerHelpers.Analyse(program);