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:
parent
03852ed2bf
commit
4d325569fa
|
@ -52,6 +52,11 @@ public abstract class PascalType : IEquatable<PascalType>
|
|||
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<PascalType>
|
|||
/// <returns>是否为可计算的类型</returns>
|
||||
public static bool IsCalculatable(PascalType pascalType)
|
||||
{
|
||||
return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real;
|
||||
return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real
|
||||
|| pascalType == PascalBasicType.Boolean;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -496,20 +496,46 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? 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) =>
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user