feat:完成语法树结点的类型检查 (#59)
Co-authored-by: jackfiled <xcrenchangjun@outlook.com> Reviewed-on: PostGuard/Canon#59 Co-authored-by: ichirinko <1621543655@qq.com> Co-committed-by: ichirinko <1621543655@qq.com>
This commit is contained in:
parent
d84b254716
commit
03852ed2bf
|
@ -35,6 +35,8 @@ public class PascalBasicType : PascalType
|
||||||
return Type.GetHashCode();
|
return Type.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() => TypeName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 整数类型的单例对象
|
/// 整数类型的单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
using Canon.Core.SyntaxNodes;
|
using Canon.Core.SyntaxNodes;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Expression = Canon.Core.SyntaxNodes.Expression;
|
||||||
|
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
|
@ -10,12 +11,27 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
{
|
{
|
||||||
public SymbolTable SymbolTable { get; private set; } = new();
|
public SymbolTable SymbolTable { get; private set; } = new();
|
||||||
|
|
||||||
public override void PostVisit(ConstValue constValue)
|
/// <summary>
|
||||||
|
/// 语法检查中是否发现错误
|
||||||
|
/// </summary>
|
||||||
|
public bool IsError { get; private set; }
|
||||||
|
|
||||||
|
public override void PreVisit(ConstDeclaration constDeclaration)
|
||||||
{
|
{
|
||||||
base.PostVisit(constValue);
|
base.PostVisit(constDeclaration);
|
||||||
constValue.OnNumberGenerator += (_, e) =>
|
|
||||||
|
(IdentifierSemanticToken token, ConstValue constValue) = constDeclaration.ConstValue;
|
||||||
|
|
||||||
|
// Lookahead 判断常量值的类型
|
||||||
|
if (constValue.Children.Count == 1)
|
||||||
{
|
{
|
||||||
switch (e.Token.NumberType)
|
SemanticToken valueToken = constValue.Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||||
|
|
||||||
|
switch (valueToken.TokenType)
|
||||||
|
{
|
||||||
|
case SemanticTokenType.Number:
|
||||||
|
NumberSemanticToken numberSemanticToken = valueToken.Convert<NumberSemanticToken>();
|
||||||
|
switch (numberSemanticToken.NumberType)
|
||||||
{
|
{
|
||||||
case NumberType.Integer:
|
case NumberType.Integer:
|
||||||
constValue.ConstType = PascalBasicType.Integer;
|
constValue.ConstType = PascalBasicType.Integer;
|
||||||
|
@ -24,23 +40,35 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
constValue.ConstType = PascalBasicType.Real;
|
constValue.ConstType = PascalBasicType.Real;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
constValue.OnCharacterGenerator += (_, _) => { constValue.ConstType = PascalBasicType.Character; };
|
break;
|
||||||
|
case SemanticTokenType.Character:
|
||||||
|
constValue.ConstType = PascalBasicType.Character;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NumberSemanticToken numberSemanticToken = constValue.Children[1].Convert<TerminatedSyntaxNode>()
|
||||||
|
.Token.Convert<NumberSemanticToken>();
|
||||||
|
|
||||||
|
switch (numberSemanticToken.NumberType)
|
||||||
|
{
|
||||||
|
case NumberType.Integer:
|
||||||
|
constValue.ConstType = PascalBasicType.Integer;
|
||||||
|
break;
|
||||||
|
case NumberType.Real:
|
||||||
|
constValue.ConstType = PascalBasicType.Real;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(ConstDeclaration constDeclaration)
|
if (!SymbolTable.TryAddSymbol(new Symbol
|
||||||
{
|
|
||||||
base.PostVisit(constDeclaration);
|
|
||||||
(IdentifierSemanticToken token, ConstValue constValue) = constDeclaration.ConstValue;
|
|
||||||
|
|
||||||
bool result = SymbolTable.TryAddSymbol(new Symbol
|
|
||||||
{
|
{
|
||||||
Const = true, SymbolName = token.IdentifierName, SymbolType = constValue.ConstType
|
Const = true, SymbolName = token.IdentifierName, SymbolType = constValue.ConstType
|
||||||
});
|
}))
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
{
|
||||||
|
IsError = true;
|
||||||
logger?.LogError("Identifier '{}' has been declared twice!", token.IdentifierName);
|
logger?.LogError("Identifier '{}' has been declared twice!", token.IdentifierName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,35 +92,44 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
};
|
};
|
||||||
|
|
||||||
// factor -> variable
|
// factor -> variable
|
||||||
factor.OnVariableGenerator += (_, e) =>
|
factor.OnVariableGenerator += (_, e) => { factor.FactorType = e.Variable.VariableType; };
|
||||||
{
|
|
||||||
if (SymbolTable.TryGetSymbol(e.Variable.Identifier.IdentifierName, out Symbol? symbol))
|
|
||||||
{
|
|
||||||
factor.FactorType = symbol.SymbolType;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// factor -> (expression)
|
// factor -> (expression)
|
||||||
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExprssionType; };
|
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExpressionType; };
|
||||||
|
|
||||||
// factor -> id (expression_list)
|
// factor -> id (expression_list)
|
||||||
factor.OnProcedureCallGenerator += (_, e) =>
|
factor.OnProcedureCallGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure))
|
if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure))
|
||||||
{
|
{
|
||||||
|
IsError = true;
|
||||||
logger?.LogError("Procedure '{}' does not define.", e.ProcedureName.IdentifierName);
|
logger?.LogError("Procedure '{}' does not define.", e.ProcedureName.IdentifierName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (procedure.SymbolType is not PascalFunctionType functionType)
|
PascalFunctionType? functionType = procedure.SymbolType as PascalFunctionType;
|
||||||
|
if (functionType is null)
|
||||||
{
|
{
|
||||||
logger?.LogError("Identifier '{}' is not a call-able.", procedure.SymbolName);
|
if (SymbolTable.TryGetParent(out SymbolTable? parent))
|
||||||
|
{
|
||||||
|
if (parent.TryGetSymbol(e.ProcedureName.IdentifierName, out procedure))
|
||||||
|
{
|
||||||
|
functionType = procedure.SymbolType as PascalFunctionType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionType is null)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("'{}' is not call able.", e.ProcedureName.IdentifierName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionType.ReturnType == PascalBasicType.Void)
|
if (functionType.ReturnType == PascalBasicType.Void)
|
||||||
{
|
{
|
||||||
logger?.LogError("Procedure '{}' returns void.", procedure.SymbolName);
|
IsError = true;
|
||||||
|
logger?.LogError("Procedure '{}' returns void.", e.ProcedureName.IdentifierName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +137,9 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
|
|
||||||
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
||||||
{
|
{
|
||||||
|
IsError = true;
|
||||||
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
||||||
procedure.SymbolName,
|
e.ProcedureName.IdentifierName,
|
||||||
functionType.Parameters.Count,
|
functionType.Parameters.Count,
|
||||||
e.Parameters.Expressions.Count);
|
e.Parameters.Expressions.Count);
|
||||||
return;
|
return;
|
||||||
|
@ -110,9 +148,11 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
||||||
functionType.Parameters))
|
functionType.Parameters))
|
||||||
{
|
{
|
||||||
if (expression.ExprssionType != parameterType)
|
if (expression.ExpressionType != parameterType.ParameterType)
|
||||||
{
|
{
|
||||||
logger?.LogError("");
|
IsError = true;
|
||||||
|
logger?.LogError("Parameter expect '{}' but '{}'",
|
||||||
|
parameterType.ParameterType.TypeName, expression.ExpressionType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +163,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
{
|
{
|
||||||
if (e.Factor.FactorType != PascalBasicType.Boolean)
|
if (e.Factor.FactorType != PascalBasicType.Boolean)
|
||||||
{
|
{
|
||||||
|
IsError = true;
|
||||||
logger?.LogError("The boolean type is expected.");
|
logger?.LogError("The boolean type is expected.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -148,6 +189,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsError = true;
|
||||||
logger?.LogError("Can't calculate");
|
logger?.LogError("Can't calculate");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -166,6 +208,7 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IsError = true;
|
||||||
logger?.LogError("Can't calculate");
|
logger?.LogError("Can't calculate");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -176,10 +219,10 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
|
|
||||||
expression.OnSimpleExpressionGenerator += (_, e) =>
|
expression.OnSimpleExpressionGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
expression.ExprssionType = e.SimpleExpression.SimpleExpressionType;
|
expression.ExpressionType = e.SimpleExpression.SimpleExpressionType;
|
||||||
};
|
};
|
||||||
|
|
||||||
expression.OnRelationGenerator += (_, _) => { expression.ExprssionType = PascalBasicType.Boolean; };
|
expression.OnRelationGenerator += (_, _) => { expression.ExpressionType = PascalBasicType.Boolean; };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(TypeSyntaxNode typeSyntaxNode)
|
public override void PostVisit(TypeSyntaxNode typeSyntaxNode)
|
||||||
|
@ -232,7 +275,6 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
SymbolName = e.IdentifierToken.IdentifierName,
|
SymbolName = e.IdentifierToken.IdentifierName,
|
||||||
SymbolType = identifierList.DefinitionType,
|
SymbolType = identifierList.DefinitionType,
|
||||||
Reference = identifierList.IsReference
|
Reference = identifierList.IsReference
|
||||||
|
|
||||||
};
|
};
|
||||||
SymbolTable.TryAddSymbol(symbol);
|
SymbolTable.TryAddSymbol(symbol);
|
||||||
|
|
||||||
|
@ -333,6 +375,12 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
SymbolName = subprogramHead.SubprogramName.IdentifierName,
|
SymbolName = subprogramHead.SubprogramName.IdentifierName,
|
||||||
SymbolType = new PascalFunctionType(parameters, e.ReturnType.PascalType)
|
SymbolType = new PascalFunctionType(parameters, e.ReturnType.PascalType)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 在Pascal中返回值是添加一个类型为返回类型 名称为函数名称的局部变量
|
||||||
|
SymbolTable.TryAddSymbol(new Symbol
|
||||||
|
{
|
||||||
|
SymbolName = subprogramHead.SubprogramName.IdentifierName, SymbolType = e.ReturnType.PascalType
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,4 +419,173 @@ public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : Syntax
|
||||||
// 同时添加到参数列表
|
// 同时添加到参数列表
|
||||||
_parameters!.Add(symbol);
|
_parameters!.Add(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void PostVisit(Statement statement)
|
||||||
|
{
|
||||||
|
base.PostVisit(statement);
|
||||||
|
// statement -> Variable AssignOp Expression
|
||||||
|
|
||||||
|
statement.OnAssignGenerator += (_, e) =>
|
||||||
|
{
|
||||||
|
// 检查是否有注册变量
|
||||||
|
if (!SymbolTable.TryGetSymbol(e.Variable.Identifier.IdentifierName, out Symbol? variable))
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Variable '{}' does not define.", e.Variable.Identifier.IdentifierName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为常量
|
||||||
|
if (variable.Const)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Can't assign value to const '{}'.,",
|
||||||
|
e.Variable.Identifier.IdentifierName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.Variable.VariableType != e.Expression.ExpressionType)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Variable '{}' type mismatch, expect '{}' but '{}'.",
|
||||||
|
e.Variable.Identifier.IdentifierName,
|
||||||
|
e.Variable.VariableType.ToString(),
|
||||||
|
e.Expression.ExpressionType.ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// statement -> for id AssignOp Expression to Expression do Statement
|
||||||
|
statement.OnForGenerator += (_, e) =>
|
||||||
|
{
|
||||||
|
// 检查id是否存在
|
||||||
|
if (!SymbolTable.TryGetSymbol(e.Iterator.IdentifierName, out Symbol? _))
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Variable '{}' does not define.", e.Iterator.IdentifierName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查ExpressionA是否为Integer
|
||||||
|
if (e.Begin.ExpressionType != PascalBasicType.Integer)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("The loop begin parameter is not integer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查ExpressionB是否为Integer
|
||||||
|
if (e.End.ExpressionType != PascalBasicType.Integer)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("The loop end parameter is not integer.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// statement -> if Expression then Statement ElsePart
|
||||||
|
statement.OnIfGenerator += (_, e) =>
|
||||||
|
{
|
||||||
|
// 条件是否为Boolean
|
||||||
|
if (e.Condition.ExpressionType != PascalBasicType.Boolean)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Expect '{}' but '{}'.", PascalBasicType.Boolean.TypeName,
|
||||||
|
e.Condition.ExpressionType.ToString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostVisit(ProcedureCall procedureCall)
|
||||||
|
{
|
||||||
|
base.PostVisit(procedureCall);
|
||||||
|
// 查看procedureId是否注册
|
||||||
|
if (!SymbolTable.TryGetSymbol(procedureCall.ProcedureId.IdentifierName, out Symbol? procedure))
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("procedure '{}' is not defined.", procedureCall.ProcedureId.IdentifierName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看该符号是否为procedure
|
||||||
|
if (procedure.SymbolType is not PascalFunctionType functionType)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Identifier '{}' is not a call-able.", procedure.SymbolName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
procedureCall.OnParameterGenerator += (_, e) =>
|
||||||
|
{
|
||||||
|
// 检查procedure输入参数个数是否相符
|
||||||
|
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
||||||
|
procedure.SymbolName,
|
||||||
|
functionType.Parameters.Count,
|
||||||
|
e.Parameters.Expressions.Count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查每个参数的类型与procedure参数定义类型是否相符
|
||||||
|
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
||||||
|
functionType.Parameters))
|
||||||
|
{
|
||||||
|
if (expression.ExpressionType != parameterType.ParameterType)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Parameter expect '{}' but '{}'",
|
||||||
|
parameterType.ParameterType.TypeName, expression.ExpressionType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostVisit(Variable variable)
|
||||||
|
{
|
||||||
|
base.PostVisit(variable);
|
||||||
|
if (SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out Symbol? id))
|
||||||
|
{
|
||||||
|
variable.VariableType = id.SymbolType;
|
||||||
|
|
||||||
|
for (int i = 0; i < variable.VarPart.IndexCount; i++)
|
||||||
|
{
|
||||||
|
if (variable.VariableType is PascalArrayType arrayType)
|
||||||
|
{
|
||||||
|
variable.VariableType = arrayType.ElementType;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 提前不为ArrayType,赋值变量维数写多
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Array dimension mismatch, more than expect");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 没有注册变量
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Variable '{}' does not define.", variable.Identifier.IdentifierName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostVisit(IdentifierVarPart identifierVarPart)
|
||||||
|
{
|
||||||
|
base.PostVisit(identifierVarPart);
|
||||||
|
identifierVarPart.OnIndexGenerator += (_, e) =>
|
||||||
|
{
|
||||||
|
foreach (Expression expression in e.IndexParameters.Expressions)
|
||||||
|
{
|
||||||
|
if (expression.ExpressionType != PascalBasicType.Integer)
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Index of array expect 'int' but '{}'",
|
||||||
|
expression.ExpressionType.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
identifierVarPart.IndexCount = e.IndexParameters.Expressions.Count;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
@ -8,8 +7,6 @@ public class CompoundStatement : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.CompoundStatement;
|
public override NonTerminatorType Type => NonTerminatorType.CompoundStatement;
|
||||||
|
|
||||||
public IEnumerable<Statement> Statements => Children[1].Convert<StatementList>().Statements;
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -24,16 +21,4 @@ public class CompoundStatement : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new CompoundStatement { Children = children };
|
return new CompoundStatement { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
foreach (var statement in Statements.Reverse())
|
|
||||||
{
|
|
||||||
if (statement.Children.Count > 0)
|
|
||||||
{
|
|
||||||
statement.GenerateCCode(builder);
|
|
||||||
builder.AddString(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -9,11 +7,6 @@ public class ConstDeclarations : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.ConstDeclarations;
|
public override NonTerminatorType Type => NonTerminatorType.ConstDeclarations;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 声明的常量列表
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<(IdentifierSemanticToken, ConstValue)> ConstValues => GetConstValues();
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -28,62 +21,4 @@ public class ConstDeclarations : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new ConstDeclarations { Children = children };
|
return new ConstDeclarations { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<(IdentifierSemanticToken, ConstValue)> GetConstValues()
|
|
||||||
{
|
|
||||||
if (Children.Count == 0)
|
|
||||||
{
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstDeclaration declaration = Children[1].Convert<ConstDeclaration>();
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
yield return declaration.ConstValue;
|
|
||||||
|
|
||||||
if (declaration.IsRecursive)
|
|
||||||
{
|
|
||||||
declaration = declaration.Children[0].Convert<ConstDeclaration>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
foreach (var pair in ConstValues.Reverse())
|
|
||||||
{
|
|
||||||
builder.AddString(" const");
|
|
||||||
//获取常量类型
|
|
||||||
var token = pair.Item2.Children[0].Convert<TerminatedSyntaxNode>().Token;
|
|
||||||
var tokenType = token.TokenType;
|
|
||||||
if (tokenType == SemanticTokenType.Number)
|
|
||||||
{
|
|
||||||
if (token.Convert<NumberSemanticToken>().NumberType == NumberType.Integer)
|
|
||||||
{
|
|
||||||
builder.AddString(" int ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.AddString(" double ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (tokenType == SemanticTokenType.Character)
|
|
||||||
{
|
|
||||||
builder.AddString(" char ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.AddString(" bool ");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AddString(pair.Item1.IdentifierName + " =");
|
|
||||||
pair.Item2.GenerateCCode(builder);
|
|
||||||
builder.AddString(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class Expression : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
private PascalType? _expressionType;
|
private PascalType? _expressionType;
|
||||||
|
|
||||||
public PascalType ExprssionType
|
public PascalType ExpressionType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,11 @@ using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
public class OnExpressionListEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public required ExpressionList ExpressionList { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
public class ExpressionList : NonTerminatedSyntaxNode
|
public class ExpressionList : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.ExpressionList;
|
public override NonTerminatorType Type => NonTerminatorType.ExpressionList;
|
||||||
|
@ -12,26 +17,40 @@ public class ExpressionList : NonTerminatedSyntaxNode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Expression> Expressions { get; } = [];
|
public List<Expression> Expressions { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前ExpressionList中的Expression定义
|
||||||
|
/// </summary>
|
||||||
|
public required Expression Expression { get; init; }
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PostVisit(this);
|
visitor.PostVisit(this);
|
||||||
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用ExpressionList产生式的时间
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<OnExpressionListEventArgs>? OnExpressionList;
|
||||||
|
|
||||||
public static ExpressionList Create(List<SyntaxNodeBase> children)
|
public static ExpressionList Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
ExpressionList result = new() { Children = children };
|
ExpressionList result;
|
||||||
|
|
||||||
if (children.Count == 1)
|
if (children.Count == 1)
|
||||||
{
|
{
|
||||||
|
result = new ExpressionList { Expression = children[0].Convert<Expression>(), Children = children };
|
||||||
result.Expressions.Add(children[0].Convert<Expression>());
|
result.Expressions.Add(children[0].Convert<Expression>());
|
||||||
}
|
}
|
||||||
else if (children.Count == 3)
|
else
|
||||||
{
|
{
|
||||||
|
result = new ExpressionList { Expression = children[2].Convert<Expression>(), Children = children };
|
||||||
foreach (Expression expression in children[0].Convert<ExpressionList>().Expressions)
|
foreach (Expression expression in children[0].Convert<ExpressionList>().Expressions)
|
||||||
{
|
{
|
||||||
result.Expressions.Add(expression);
|
result.Expressions.Add(expression);
|
||||||
|
@ -42,4 +61,15 @@ public class ExpressionList : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RaiseEvent()
|
||||||
|
{
|
||||||
|
if (Children.Count == 3)
|
||||||
|
{
|
||||||
|
OnExpressionList?.Invoke(this,
|
||||||
|
new OnExpressionListEventArgs { ExpressionList = Children[0].Convert<ExpressionList>() });
|
||||||
|
}
|
||||||
|
|
||||||
|
OnExpressionList = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,20 @@ using Canon.Core.Enums;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
public class OnParameterGeneratorEventArgs : EventArgs
|
public class OnIndexGeneratorEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public required ExpressionList Parameters { get; init; }
|
public required ExpressionList IndexParameters { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class IdentifierVarPart : NonTerminatedSyntaxNode
|
public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.IdVarPart;
|
public override NonTerminatorType Type => NonTerminatorType.IdVarPart;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数组索引的个数
|
||||||
|
/// </summary>
|
||||||
|
public int IndexCount { get; set; }
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -24,7 +29,10 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||||
RaiseEvent();
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<OnParameterGeneratorEventArgs>? OnParameterGenerator;
|
/// <summary>
|
||||||
|
/// 使用了索引产生式的事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<OnIndexGeneratorEventArgs>? OnIndexGenerator;
|
||||||
|
|
||||||
public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
|
public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
|
@ -35,12 +43,12 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
if (Children.Count == 3)
|
if (Children.Count == 3)
|
||||||
{
|
{
|
||||||
OnParameterGenerator?.Invoke(this, new OnParameterGeneratorEventArgs
|
OnIndexGenerator?.Invoke(this, new OnIndexGeneratorEventArgs()
|
||||||
{
|
{
|
||||||
Parameters = Children[1].Convert<ExpressionList>()
|
IndexParameters = Children[1].Convert<ExpressionList>()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
OnParameterGenerator = null;
|
OnIndexGenerator = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ public abstract class NonTerminatedSyntaxNode : SyntaxNodeBase, IEnumerable<Synt
|
||||||
|
|
||||||
public abstract NonTerminatorType Type { get; }
|
public abstract NonTerminatorType Type { get; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public required List<SyntaxNodeBase> Children { get; init; }
|
public required List<SyntaxNodeBase> Children { get; init; }
|
||||||
|
|
||||||
public IEnumerator<SyntaxNodeBase> GetEnumerator()
|
public IEnumerator<SyntaxNodeBase> GetEnumerator()
|
||||||
|
|
|
@ -7,13 +7,6 @@ public class ParameterList : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.ParameterList;
|
public override NonTerminatorType Type => NonTerminatorType.ParameterList;
|
||||||
|
|
||||||
public bool IsRecursive { get; private init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 声明的参数列表
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Parameter> Parameters => GetParameters();
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -26,40 +19,6 @@ public class ParameterList : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
public static ParameterList Create(List<SyntaxNodeBase> children)
|
public static ParameterList Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
bool isRecursive;
|
return new ParameterList { Children = children };
|
||||||
|
|
||||||
if (children.Count == 1)
|
|
||||||
{
|
|
||||||
isRecursive = false;
|
|
||||||
}
|
|
||||||
else if (children.Count == 3)
|
|
||||||
{
|
|
||||||
isRecursive = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ParameterList { Children = children, IsRecursive = isRecursive };
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Parameter> GetParameters()
|
|
||||||
{
|
|
||||||
ParameterList list = this;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (list.IsRecursive)
|
|
||||||
{
|
|
||||||
yield return list.Children[2].Convert<Parameter>();
|
|
||||||
list = list.Children[0].Convert<ParameterList>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yield return list.Children[0].Convert<Parameter>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,36 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
public class OnParameterGeneratorEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public required ExpressionList Parameters { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
public class ProcedureCall : NonTerminatedSyntaxNode
|
public class ProcedureCall : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.ProcedureCall;
|
public override NonTerminatorType Type => NonTerminatorType.ProcedureCall;
|
||||||
|
|
||||||
public IdentifierSemanticToken ProcedureId
|
public IdentifierSemanticToken ProcedureId
|
||||||
=> (IdentifierSemanticToken)Children[0].Convert<TerminatedSyntaxNode>().Token;
|
=> Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>();
|
||||||
|
|
||||||
public IEnumerable<Expression> Arguments => GetArguments();
|
/// <summary>
|
||||||
|
/// 调用函数时含有参数的事件
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<OnParameterGeneratorEventArgs>? OnParameterGenerator;
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PostVisit(this);
|
visitor.PostVisit(this);
|
||||||
|
RaiseEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProcedureCall Create(List<SyntaxNodeBase> children)
|
public static ProcedureCall Create(List<SyntaxNodeBase> children)
|
||||||
|
@ -29,38 +38,16 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
||||||
return new ProcedureCall { Children = children };
|
return new ProcedureCall { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Expression> GetArguments()
|
private void RaiseEvent()
|
||||||
{
|
{
|
||||||
if (Children.Count == 1)
|
if (Children.Count == 4)
|
||||||
{
|
{
|
||||||
yield break;
|
OnParameterGenerator?.Invoke(this, new OnParameterGeneratorEventArgs
|
||||||
|
{
|
||||||
|
Parameters = Children[2].Convert<ExpressionList>()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Expression expression in Children[2].Convert<ExpressionList>().Expressions)
|
OnParameterGenerator = null;
|
||||||
{
|
|
||||||
yield return expression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
builder.AddString(ProcedureId.IdentifierName + "(");
|
|
||||||
|
|
||||||
//用逗号分隔输出的expression
|
|
||||||
using (var enumerator = Arguments.GetEnumerator())
|
|
||||||
{
|
|
||||||
if (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
enumerator.Current.GenerateCCode(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
builder.AddString(", ");
|
|
||||||
enumerator.Current.GenerateCCode(builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AddString(")");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class Statement : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
private void RaiseEvent()
|
private void RaiseEvent()
|
||||||
{
|
{
|
||||||
if (Children.Count == 2)
|
if (Children.Count == 3)
|
||||||
{
|
{
|
||||||
if (Children[0].IsTerminated)
|
if (Children[0].IsTerminated)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,10 +8,6 @@ public class StatementList : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.StatementList;
|
public override NonTerminatorType Type => NonTerminatorType.StatementList;
|
||||||
|
|
||||||
public bool IsRecursive { get; private init; }
|
|
||||||
|
|
||||||
public IEnumerable<Statement> Statements => GetStatements();
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -24,52 +20,6 @@ public class StatementList : NonTerminatedSyntaxNode
|
||||||
|
|
||||||
public static StatementList Create(List<SyntaxNodeBase> children)
|
public static StatementList Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
bool isRecursive;
|
return new StatementList { Children = children};
|
||||||
|
|
||||||
if (children.Count == 1)
|
|
||||||
{
|
|
||||||
isRecursive = false;
|
|
||||||
}
|
|
||||||
else if (children.Count == 3)
|
|
||||||
{
|
|
||||||
isRecursive = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StatementList { Children = children, IsRecursive = isRecursive };
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Statement> GetStatements()
|
|
||||||
{
|
|
||||||
StatementList list = this;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (list.IsRecursive)
|
|
||||||
{
|
|
||||||
yield return list.Children[2].Convert<Statement>();
|
|
||||||
list = list.Children[0].Convert<StatementList>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yield return list.Children[0].Convert<Statement>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
foreach (var statement in Statements.Reverse())
|
|
||||||
{
|
|
||||||
if (statement.Children.Count > 0)
|
|
||||||
{
|
|
||||||
statement.GenerateCCode(builder);
|
|
||||||
builder.AddString(";");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,6 @@ public class SubprogramDeclarations : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.SubprogramDeclarations;
|
public override NonTerminatorType Type => NonTerminatorType.SubprogramDeclarations;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 声明的子程序列表
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Subprogram> Subprograms => GetSubprograms();
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -27,28 +22,4 @@ public class SubprogramDeclarations : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new SubprogramDeclarations { Children = children };
|
return new SubprogramDeclarations { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Subprogram> GetSubprograms()
|
|
||||||
{
|
|
||||||
SubprogramDeclarations declarations = this;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (declarations.Children.Count == 0)
|
|
||||||
{
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return declarations.Children[1].Convert<Subprogram>();
|
|
||||||
declarations = declarations.Children[0].Convert<SubprogramDeclarations>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
{
|
|
||||||
foreach (var subprogram in Subprograms)
|
|
||||||
{
|
|
||||||
subprogram.GenerateCCode(builder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.CodeGenerators;
|
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.SemanticParser;
|
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -9,11 +7,6 @@ public class VarDeclarations : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.VarDeclarations;
|
public override NonTerminatorType Type => NonTerminatorType.VarDeclarations;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 声明的变量列表
|
|
||||||
/// </summary>
|
|
||||||
// public IEnumerable<(IdentifierList, TypeSyntaxNode)> Variables => EnumerateVariables();
|
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
@ -28,73 +21,4 @@ public class VarDeclarations : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
return new VarDeclarations { Children = children };
|
return new VarDeclarations { Children = children };
|
||||||
}
|
}
|
||||||
|
|
||||||
// private IEnumerable<(IdentifierList, TypeSyntaxNode)> EnumerateVariables()
|
|
||||||
// {
|
|
||||||
// if (Children.Count == 0)
|
|
||||||
// {
|
|
||||||
// yield break;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// VarDeclaration declaration = Children[1].Convert<VarDeclaration>();
|
|
||||||
//
|
|
||||||
// while (true)
|
|
||||||
// {
|
|
||||||
// yield return declaration.Variable;
|
|
||||||
//
|
|
||||||
// if (declaration.IsRecursive)
|
|
||||||
// {
|
|
||||||
// declaration = declaration.Children[0].Convert<VarDeclaration>();
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public override void GenerateCCode(CCodeBuilder builder)
|
|
||||||
// {
|
|
||||||
// foreach (var pair in Variables.Reverse())
|
|
||||||
// {
|
|
||||||
// //BasicType定义
|
|
||||||
// if (pair.Item2.Children.Count == 1)
|
|
||||||
// {
|
|
||||||
// //输出类型
|
|
||||||
// pair.Item2.GenerateCCode(builder);
|
|
||||||
// //输出idList
|
|
||||||
// pair.Item1.GenerateCCode(builder);
|
|
||||||
// builder.AddString(";");
|
|
||||||
// }
|
|
||||||
// //array定义
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// //构造出C语言形式的数组下标定义
|
|
||||||
// string arrayPeriod = "";
|
|
||||||
// var ranges = pair.Item2.Children[2]
|
|
||||||
// .Convert<Period>().Ranges;
|
|
||||||
// PascalType pascalType = pair.Item2.Children[5].Convert<BasicType>().TryGetPascalType();
|
|
||||||
//
|
|
||||||
// foreach (var range in ranges)
|
|
||||||
// {
|
|
||||||
// int low = int.Parse(range.Item1.LiteralValue);
|
|
||||||
// int high = int.Parse(range.Item2.LiteralValue);
|
|
||||||
// arrayPeriod = "[" + System.Convert.ToString(high-low+1) + "]" + arrayPeriod;
|
|
||||||
// pascalType = new PascalArrayType(pascalType, low, high); //嵌套地构造出多维数组
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// //依次定义每一个符号
|
|
||||||
// foreach (var id in pair.Item1.Identifiers.Reverse())
|
|
||||||
// {
|
|
||||||
// pair.Item2.Children[5].GenerateCCode(builder);
|
|
||||||
// builder.AddString(" " + id.IdentifierName + arrayPeriod + ";");
|
|
||||||
// //写入符号表
|
|
||||||
// builder.SymbolTable.TryAddSymbol(new Symbol()
|
|
||||||
// {
|
|
||||||
// SymbolName = id.IdentifierName, SymbolType = pascalType, Reference = false
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Canon.Core.Abstractions;
|
using Canon.Core.Abstractions;
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
|
using Canon.Core.SemanticParser;
|
||||||
|
|
||||||
namespace Canon.Core.SyntaxNodes;
|
namespace Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
|
@ -8,12 +9,39 @@ public class Variable : NonTerminatedSyntaxNode
|
||||||
{
|
{
|
||||||
public override NonTerminatorType Type => NonTerminatorType.Variable;
|
public override NonTerminatorType Type => NonTerminatorType.Variable;
|
||||||
|
|
||||||
|
private PascalType? _variableType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Variable实际的类型,用于数组赋值
|
||||||
|
/// </summary>
|
||||||
|
public PascalType VariableType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_variableType is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _variableType;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_variableType = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 变量的名称
|
/// 变量的名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IdentifierSemanticToken Identifier =>
|
public IdentifierSemanticToken Identifier =>
|
||||||
(IdentifierSemanticToken)Children[0].Convert<TerminatedSyntaxNode>().Token;
|
(IdentifierSemanticToken)Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 声明数组访问的部分
|
||||||
|
/// </summary>
|
||||||
|
public IdentifierVarPart VarPart => Children[1].Convert<IdentifierVarPart>();
|
||||||
|
|
||||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||||
{
|
{
|
||||||
visitor.PreVisit(this);
|
visitor.PreVisit(this);
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
using Canon.Core.SemanticParser;
|
using Canon.Core.SemanticParser;
|
||||||
using Canon.Core.SyntaxNodes;
|
using Canon.Core.SyntaxNodes;
|
||||||
using Canon.Tests.Utils;
|
using Canon.Tests.Utils;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Canon.Tests.SemanticTests;
|
namespace Canon.Tests.SemanticTests;
|
||||||
|
|
||||||
public class TypeCheckVisitorTests
|
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
{
|
{
|
||||||
|
private readonly TestLogger<TypeCheckVisitor> _logger = new(testOutputHelper);
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ConstTypeTest()
|
public void ConstTypeTest()
|
||||||
{
|
{
|
||||||
|
@ -293,10 +296,220 @@ public class TypeCheckVisitorTests
|
||||||
Assert.False(visitor.SymbolTable.TryGetSymbol("d", out symbol));
|
Assert.False(visitor.SymbolTable.TryGetSymbol("d", out symbol));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TypeCheckVisitor CheckType(string program)
|
[Fact]
|
||||||
|
public void VarAssignStatementTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var
|
||||||
|
a : char;
|
||||||
|
b : integer;
|
||||||
|
begin
|
||||||
|
b := 3;
|
||||||
|
a := b;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryConstAssignStatementTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
const
|
||||||
|
a = 3;
|
||||||
|
var
|
||||||
|
b : integer;
|
||||||
|
begin
|
||||||
|
a := 4;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FunctionAssignStatementTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program exFunction;
|
||||||
|
var
|
||||||
|
a, b, ret : integer;
|
||||||
|
|
||||||
|
|
||||||
|
function max(num1, num2: integer): integer;
|
||||||
|
var
|
||||||
|
error:char;
|
||||||
|
result: integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if (num1 > num2) then
|
||||||
|
result := num1
|
||||||
|
|
||||||
|
else
|
||||||
|
result := num2;
|
||||||
|
max := error;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
a := 100;
|
||||||
|
b := 200;
|
||||||
|
(* calling a function to get max value *)
|
||||||
|
ret := max(a, b);
|
||||||
|
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IfStatementTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program exFunction;
|
||||||
|
var
|
||||||
|
a, b, ret : integer;
|
||||||
|
begin
|
||||||
|
a := 100;
|
||||||
|
b := 200;
|
||||||
|
if 200 then
|
||||||
|
begin
|
||||||
|
b := 100;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
b:=200;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ForStatementTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program exFunction;
|
||||||
|
var
|
||||||
|
a, b, ret : integer;
|
||||||
|
c : char;
|
||||||
|
begin
|
||||||
|
|
||||||
|
for a := c to b do
|
||||||
|
begin
|
||||||
|
b:=b+10;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProcedureCallTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var
|
||||||
|
a, b, c, min: integer;
|
||||||
|
error:char;
|
||||||
|
procedure findMin(x, y, z: integer; var m: integer);
|
||||||
|
begin
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
findMin(a, b, c,error);
|
||||||
|
(* Procedure call *)
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ArrayAssignIndexTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : array [0..10, 0..10] of integer;
|
||||||
|
function test(a, b : integer) : integer;
|
||||||
|
begin
|
||||||
|
test := 1;
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
a[0, 1.5] := 1;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ArrayAssignDimensionTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a : array [0..10, 0..10] of integer;
|
||||||
|
begin
|
||||||
|
a[0,1,3] := 1;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ArrayAssignTypeTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var
|
||||||
|
a : array [0..10, 0..10] of integer;
|
||||||
|
b : array [0..10, 0..20] of integer;
|
||||||
|
c : integer;
|
||||||
|
d : char;
|
||||||
|
begin
|
||||||
|
a[0,1] := c;
|
||||||
|
c := b[0,5];
|
||||||
|
a[0,1] := b;
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
TypeCheckVisitor visitor = CheckType(program);
|
||||||
|
Assert.True(visitor.IsError);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ArrayCalculationTest()
|
||||||
|
{
|
||||||
|
const string program = """
|
||||||
|
program main;
|
||||||
|
var a: array[9..12, 3..5, 6..20] of real;
|
||||||
|
b: array[0..10] of integer;
|
||||||
|
begin
|
||||||
|
a[9, 4, 20] := 3.6 + b[5];
|
||||||
|
end.
|
||||||
|
""";
|
||||||
|
|
||||||
|
CheckType(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeCheckVisitor CheckType(string program)
|
||||||
{
|
{
|
||||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||||
TypeCheckVisitor visitor = new();
|
TypeCheckVisitor visitor = new(_logger);
|
||||||
SyntaxTreeTraveller traveller = new();
|
SyntaxTreeTraveller traveller = new();
|
||||||
|
|
||||||
traveller.Travel(root, visitor);
|
traveller.Travel(root, visitor);
|
||||||
|
|
24
Canon.Tests/Utils/TestLogger.cs
Normal file
24
Canon.Tests/Utils/TestLogger.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Canon.Tests.Utils;
|
||||||
|
|
||||||
|
public class TestLogger<T>(ITestOutputHelper testOutputHelper) : ILogger<T>, IDisposable
|
||||||
|
{
|
||||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||||
|
Func<TState, Exception?, string> formatter)
|
||||||
|
{
|
||||||
|
testOutputHelper.WriteLine("{0}: {1}", logLevel, formatter(state, exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(LogLevel logLevel) => false;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user