parent
1908561d31
commit
b34383ea74
|
@ -36,7 +36,21 @@ public interface IGrammarParser
|
||||||
{
|
{
|
||||||
AnalyseState top = stack.Peek();
|
AnalyseState top = stack.Peek();
|
||||||
|
|
||||||
// 首先尝试进行归约
|
// 首先尝试进行移进
|
||||||
|
if (top.State.ShiftTable.TryGetValue(enumerator.Current, out ITransformer? next))
|
||||||
|
{
|
||||||
|
stack.Push(new AnalyseState(next, SyntaxNodeBase.Create(enumerator.Current)));
|
||||||
|
if (enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new GrammarException(stack.Peek().State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再进行归约
|
||||||
if (top.State.ReduceTable.TryGetValue(enumerator.Current, out ReduceInformation? information))
|
if (top.State.ReduceTable.TryGetValue(enumerator.Current, out ReduceInformation? information))
|
||||||
{
|
{
|
||||||
if (information.Left == Begin)
|
if (information.Left == Begin)
|
||||||
|
@ -60,20 +74,6 @@ public interface IGrammarParser
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有成功归约就进行移进
|
|
||||||
if (top.State.ShiftTable.TryGetValue(enumerator.Current, out ITransformer? next))
|
|
||||||
{
|
|
||||||
stack.Push(new AnalyseState(next, SyntaxNodeBase.Create(enumerator.Current)));
|
|
||||||
if (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new GrammarException(stack.Peek().State);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new GrammarException(stack.Peek().State, enumerator.Current);
|
throw new GrammarException(stack.Peek().State, enumerator.Current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Canon.Core.CodeGenerators;
|
||||||
using Canon.Core.Enums;
|
using Canon.Core.Enums;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
using Canon.Core.SyntaxNodes;
|
using Canon.Core.SyntaxNodes;
|
||||||
|
using BasicType = Canon.Core.Enums.BasicType;
|
||||||
|
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
|
@ -272,7 +273,9 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
|
||||||
// 虽然这里这样可能会生成来类似于 &*x 的代码
|
// 虽然这里这样可能会生成来类似于 &*x 的代码
|
||||||
// 但是可以正常运行
|
// 但是可以正常运行
|
||||||
variable.VariableName =
|
variable.VariableName =
|
||||||
symbol.Reference ? $"*{variable.Identifier.IdentifierName}" : variable.Identifier.IdentifierName;
|
symbol.SymbolType.IsReference
|
||||||
|
? $"*{variable.Identifier.IdentifierName}"
|
||||||
|
: variable.Identifier.IdentifierName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreVisit(Term term)
|
public override void PreVisit(Term term)
|
||||||
|
@ -608,8 +611,7 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
|
||||||
|
|
||||||
if (parameter.ParameterType is PascalBasicType)
|
if (parameter.ParameterType is PascalBasicType)
|
||||||
{
|
{
|
||||||
string refValue = parameter.IsVar ? "*" : string.Empty;
|
value = $"{GenerateBasicTypeString(parameter.ParameterType)} {parameter.ParameterName}";
|
||||||
value = $"{GenerateBasicTypeString(parameter.ParameterType)} {refValue}{parameter.ParameterName}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameter.ParameterType is PascalArrayType)
|
if (parameter.ParameterType is PascalArrayType)
|
||||||
|
@ -793,24 +795,9 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
|
||||||
foreach ((Expression parameter, PascalParameterType parameterType) in
|
foreach ((Expression parameter, PascalParameterType parameterType) in
|
||||||
parameters.Zip(functionType.Parameters))
|
parameters.Zip(functionType.Parameters))
|
||||||
{
|
{
|
||||||
if (parameterType.IsVar)
|
if (parameterType.ParameterType.IsReference)
|
||||||
{
|
{
|
||||||
// 这里需要判断parameter是否也为引用类型
|
parameterValue += $", &{parameter.VariableName}";
|
||||||
if (SymbolTable.TryGetSymbol(parameter.VariableName, out Symbol? parameterSymboe))
|
|
||||||
{
|
|
||||||
if (parameterSymboe.Reference)
|
|
||||||
{
|
|
||||||
parameterValue += $", {parameter.VariableName}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parameterValue += $", &{parameter.VariableName}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parameterValue += $", &{parameter.VariableName}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -851,29 +838,21 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
|
||||||
|
|
||||||
private static string GenerateBasicTypeString(PascalType pascalType)
|
private static string GenerateBasicTypeString(PascalType pascalType)
|
||||||
{
|
{
|
||||||
if (pascalType == PascalBasicType.Character)
|
if (pascalType is not PascalBasicType basicType)
|
||||||
{
|
{
|
||||||
return "char";
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pascalType == PascalBasicType.Boolean)
|
switch (basicType.Type)
|
||||||
{
|
{
|
||||||
return "bool";
|
case BasicType.Integer:
|
||||||
}
|
return basicType.IsReference ? "int *" : "int";
|
||||||
|
case BasicType.Real:
|
||||||
if (pascalType == PascalBasicType.Integer)
|
return basicType.IsReference ? "double *" : "double";
|
||||||
{
|
case BasicType.Character:
|
||||||
return "int";
|
return basicType.IsReference ? "char *" : "char";
|
||||||
}
|
case BasicType.Boolean:
|
||||||
|
return basicType.IsReference ? "bool *" : "bool";
|
||||||
if (pascalType == PascalBasicType.Real)
|
|
||||||
{
|
|
||||||
return "double";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pascalType == PascalBasicType.Void)
|
|
||||||
{
|
|
||||||
return "void";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
|
@ -10,6 +10,11 @@ public class PascalArrayType(PascalType elementType, int begin, int end) : Pasca
|
||||||
|
|
||||||
public override string TypeName => $"{ElementType.TypeName}_{Begin}_{End}";
|
public override string TypeName => $"{ElementType.TypeName}_{Begin}_{End}";
|
||||||
|
|
||||||
|
public override PascalType ToReferenceType()
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Array type can not be reference.");
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(PascalType? other)
|
public override bool Equals(PascalType? other)
|
||||||
{
|
{
|
||||||
if (other is not PascalArrayType pascalArrayType)
|
if (other is not PascalArrayType pascalArrayType)
|
||||||
|
@ -27,12 +32,13 @@ public class PascalArrayType(PascalType elementType, int begin, int end) : Pasca
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return base.Equals(pascalArrayType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return ElementType.GetHashCode()
|
return base.GetHashCode()
|
||||||
|
^ ElementType.GetHashCode()
|
||||||
^ Begin.GetHashCode()
|
^ Begin.GetHashCode()
|
||||||
^ End.GetHashCode();
|
^ End.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,16 @@ public class PascalBasicType : PascalType
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BasicType Type { get; }
|
public BasicType Type { get; }
|
||||||
|
|
||||||
public override string TypeName { get; }
|
public override string TypeName => Type.ToString();
|
||||||
|
|
||||||
private PascalBasicType(BasicType basicType, string typeName)
|
private PascalBasicType(BasicType type)
|
||||||
{
|
{
|
||||||
Type = basicType;
|
Type = type;
|
||||||
TypeName = typeName;
|
}
|
||||||
|
|
||||||
|
public override PascalType ToReferenceType()
|
||||||
|
{
|
||||||
|
return new PascalBasicType(Type) { IsReference = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(PascalType? other)
|
public override bool Equals(PascalType? other)
|
||||||
|
@ -27,12 +31,12 @@ public class PascalBasicType : PascalType
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Type == pascalBasicType.Type;
|
return Type == pascalBasicType.Type && base.Equals(pascalBasicType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return Type.GetHashCode();
|
return base.GetHashCode() ^ Type.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => TypeName;
|
public override string ToString() => TypeName;
|
||||||
|
@ -40,25 +44,25 @@ public class PascalBasicType : PascalType
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 整数类型的单例对象
|
/// 整数类型的单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static PascalType Integer => new PascalBasicType(BasicType.Integer, "integer");
|
public static PascalType Integer => new PascalBasicType(BasicType.Integer);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 布尔类型的单例对象
|
/// 布尔类型的单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static PascalType Boolean => new PascalBasicType(BasicType.Boolean, "boolean");
|
public static PascalType Boolean => new PascalBasicType(BasicType.Boolean);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 字符类型的单例对象
|
/// 字符类型的单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static PascalType Character => new PascalBasicType(BasicType.Character, "char");
|
public static PascalType Character => new PascalBasicType(BasicType.Character);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 浮点数类型的单例对象
|
/// 浮点数类型的单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static PascalType Real => new PascalBasicType(BasicType.Real, "real");
|
public static PascalType Real => new PascalBasicType(BasicType.Real);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 空类型的单例对象
|
/// 空类型的单例对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static PascalType Void => new PascalBasicType(BasicType.Void, "void");
|
public static PascalType Void => new PascalBasicType(BasicType.Void);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@ public class PascalFunctionType(List<PascalParameterType> parameters, PascalType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override PascalType ToReferenceType()
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Function type can not be reference.");
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(PascalType? other)
|
public override bool Equals(PascalType? other)
|
||||||
{
|
{
|
||||||
if (other is not PascalFunctionType functionType)
|
if (other is not PascalFunctionType functionType)
|
||||||
|
@ -49,12 +54,12 @@ public class PascalFunctionType(List<PascalParameterType> parameters, PascalType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return base.Equals(functionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
int code = ReturnType.GetHashCode();
|
int code = base.GetHashCode() ^ ReturnType.GetHashCode();
|
||||||
|
|
||||||
foreach (PascalParameterType parameter in Parameters)
|
foreach (PascalParameterType parameter in Parameters)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,26 +1,16 @@
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
public class PascalParameterType(PascalType parameterType, bool isVar, string parameterName) : PascalType
|
public class PascalParameterType(PascalType parameterType, string parameterName) : PascalType
|
||||||
{
|
{
|
||||||
public PascalType ParameterType { get; } = parameterType;
|
public PascalType ParameterType { get; } = parameterType;
|
||||||
|
|
||||||
public bool IsVar { get; } = isVar;
|
|
||||||
|
|
||||||
public string ParameterName { get; } = parameterName;
|
public string ParameterName { get; } = parameterName;
|
||||||
|
|
||||||
public override string TypeName
|
public override string TypeName => $"{ParameterType}_{ParameterName}";
|
||||||
|
|
||||||
|
public override PascalType ToReferenceType()
|
||||||
{
|
{
|
||||||
get
|
throw new InvalidOperationException("The parameter type can not be reference.");
|
||||||
{
|
|
||||||
if (IsVar)
|
|
||||||
{
|
|
||||||
return $"var_{ParameterType.TypeName}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ParameterType.TypeName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(PascalType? other)
|
public override bool Equals(PascalType? other)
|
||||||
|
@ -30,11 +20,11 @@ public class PascalParameterType(PascalType parameterType, bool isVar, string pa
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParameterType == parameterType.ParameterType && IsVar == parameterType.IsVar;
|
return ParameterType == parameterType.ParameterType && base.Equals(parameterType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return ParameterType.GetHashCode() ^ IsVar.GetHashCode();
|
return base.GetHashCode() ^ ParameterType.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace Canon.Core.SemanticParser;
|
using Canon.Core.Enums;
|
||||||
|
|
||||||
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pascal类型基类
|
/// Pascal类型基类
|
||||||
|
@ -10,6 +12,18 @@ public abstract class PascalType : IEquatable<PascalType>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract string TypeName { get; }
|
public abstract string TypeName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将当前类型转换为引用类型
|
||||||
|
/// 原有类型变量保持不变
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>原有Pascal类型的引用类型</returns>
|
||||||
|
public abstract PascalType ToReferenceType();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否为引用类型
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReference { get; init; }
|
||||||
|
|
||||||
public virtual bool Equals(PascalType? other)
|
public virtual bool Equals(PascalType? other)
|
||||||
{
|
{
|
||||||
if (other is null)
|
if (other is null)
|
||||||
|
@ -17,7 +31,7 @@ public abstract class PascalType : IEquatable<PascalType>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypeName == other.TypeName;
|
return IsReference == other.IsReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Convert<T>() where T : PascalType
|
public T Convert<T>() where T : PascalType
|
||||||
|
@ -42,7 +56,7 @@ public abstract class PascalType : IEquatable<PascalType>
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return TypeName.GetHashCode();
|
return IsReference.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==(PascalType a, PascalType b)
|
public static bool operator ==(PascalType a, PascalType b)
|
||||||
|
@ -57,34 +71,21 @@ public abstract class PascalType : IEquatable<PascalType>
|
||||||
|
|
||||||
public static PascalType operator +(PascalType a, PascalType b)
|
public static PascalType operator +(PascalType a, PascalType b)
|
||||||
{
|
{
|
||||||
if (!IsCalculatable(a) || !IsCalculatable(b))
|
if (a is PascalBasicType { Type: BasicType.Boolean } && b is PascalBasicType { Type: BasicType.Boolean })
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a == PascalBasicType.Boolean && b == PascalBasicType.Boolean)
|
|
||||||
{
|
{
|
||||||
return PascalBasicType.Boolean;
|
return PascalBasicType.Boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == PascalBasicType.Integer && b == PascalBasicType.Integer)
|
if (a is PascalBasicType { Type: BasicType.Integer } && b is PascalBasicType { Type: BasicType.Integer })
|
||||||
{
|
{
|
||||||
return PascalBasicType.Integer;
|
return PascalBasicType.Integer;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (a is PascalBasicType { Type : BasicType.Real } && b is PascalBasicType { Type: BasicType.Real })
|
||||||
{
|
{
|
||||||
return PascalBasicType.Real;
|
return PascalBasicType.Real;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
return PascalBasicType.Void;
|
||||||
/// 是否为可计算的类型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pascalType">需要判断的Pascal类型</param>
|
|
||||||
/// <returns>是否为可计算的类型</returns>
|
|
||||||
public static bool IsCalculatable(PascalType pascalType)
|
|
||||||
{
|
|
||||||
return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real
|
|
||||||
|| pascalType == PascalBasicType.Boolean;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,6 @@ public class Symbol : IEquatable<Symbol>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Const { get; init; }
|
public bool Const { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为引用变量
|
|
||||||
/// </summary>
|
|
||||||
public bool Reference { get; init; }
|
|
||||||
|
|
||||||
public bool Equals(Symbol? other)
|
public bool Equals(Symbol? other)
|
||||||
{
|
{
|
||||||
if (other is null)
|
if (other is null)
|
||||||
|
@ -33,9 +28,8 @@ public class Symbol : IEquatable<Symbol>
|
||||||
}
|
}
|
||||||
|
|
||||||
return SymbolName == other.SymbolName
|
return SymbolName == other.SymbolName
|
||||||
&& SymbolType == other.SymbolType
|
&& SymbolType == other.SymbolType
|
||||||
&& Const == other.Const
|
&& Const == other.Const;
|
||||||
&& Reference == other.Reference;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
|
@ -53,6 +47,3 @@ public class Symbol : IEquatable<Symbol>
|
||||||
return Equals(other);
|
return Equals(other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
|
|
||||||
if (!SymbolTable.TryAddSymbol(new Symbol
|
if (!SymbolTable.TryAddSymbol(new Symbol
|
||||||
{
|
{
|
||||||
Const = true, SymbolName = token.IdentifierName, SymbolType = constValue.ConstType
|
SymbolName = token.IdentifierName, SymbolType = constValue.ConstType, Const = true
|
||||||
}))
|
}))
|
||||||
{
|
{
|
||||||
IsError = true;
|
IsError = true;
|
||||||
|
@ -96,23 +96,14 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
};
|
};
|
||||||
|
|
||||||
// factor -> true | false
|
// factor -> true | false
|
||||||
factor.OnBooleanGenerator += (_, _) =>
|
factor.OnBooleanGenerator += (_, _) => { factor.VariableType = PascalBasicType.Boolean; };
|
||||||
{
|
|
||||||
factor.VariableType = PascalBasicType.Boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
// factor -> variable
|
// factor -> variable
|
||||||
factor.OnVariableGenerator += (_, e) =>
|
factor.OnVariableGenerator += (_, e) => { factor.VariableType = e.Variable.VariableType; };
|
||||||
{
|
|
||||||
factor.VariableType = e.Variable.VariableType;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// factor -> (expression)
|
// factor -> (expression)
|
||||||
factor.OnParethnesisGenerator += (_, e) =>
|
factor.OnParethnesisGenerator += (_, e) => { factor.VariableType = e.Expression.VariableType; };
|
||||||
{
|
|
||||||
factor.VariableType = e.Expression.VariableType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// factor -> id ( ExpressionList)
|
// factor -> id ( ExpressionList)
|
||||||
factor.OnProcedureCallGenerator += (_, e) =>
|
factor.OnProcedureCallGenerator += (_, e) =>
|
||||||
|
@ -135,43 +126,30 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
};
|
};
|
||||||
|
|
||||||
// factor -> not factor
|
// factor -> not factor
|
||||||
factor.OnNotGenerator += (_, e) =>
|
factor.OnNotGenerator += (_, e) => { factor.VariableType = e.Factor.VariableType; };
|
||||||
{
|
|
||||||
factor.VariableType = e.Factor.VariableType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// factor -> uminus factor
|
// factor -> uminus factor
|
||||||
factor.OnUminusGenerator += (_, e) =>
|
factor.OnUminusGenerator += (_, e) => { factor.VariableType = e.Factor.VariableType; };
|
||||||
{
|
|
||||||
factor.VariableType = e.Factor.VariableType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// factor -> plus factor
|
// factor -> plus factor
|
||||||
factor.OnPlusGenerator += (_, e) =>
|
factor.OnPlusGenerator += (_, e) => { factor.VariableType = e.Factor.VariableType; };
|
||||||
{
|
|
||||||
factor.VariableType = e.Factor.VariableType;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(Term term)
|
public override void PostVisit(Term term)
|
||||||
{
|
{
|
||||||
base.PostVisit(term);
|
base.PostVisit(term);
|
||||||
|
|
||||||
term.OnFactorGenerator += (_, e) =>
|
term.OnFactorGenerator += (_, e) => { term.VariableType = e.Factor.VariableType; };
|
||||||
{
|
|
||||||
term.VariableType = e.Factor.VariableType;
|
|
||||||
};
|
|
||||||
|
|
||||||
term.OnMultiplyGenerator += (_, e) =>
|
term.OnMultiplyGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
if (PascalType.IsCalculatable(e.Left.VariableType) && PascalType.IsCalculatable(e.Right.VariableType))
|
term.VariableType = e.Left.VariableType + e.Right.VariableType;
|
||||||
{
|
|
||||||
term.VariableType = e.Left.VariableType + e.Right.VariableType;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsError = true;
|
if (term.VariableType == PascalBasicType.Void)
|
||||||
logger?.LogError("Can't calculate");
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Can't calculate");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,21 +157,17 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
{
|
{
|
||||||
base.PostVisit(simpleExpression);
|
base.PostVisit(simpleExpression);
|
||||||
|
|
||||||
simpleExpression.OnTermGenerator += (_, e) =>
|
simpleExpression.OnTermGenerator += (_, e) => { simpleExpression.VariableType = e.Term.VariableType; };
|
||||||
{
|
|
||||||
simpleExpression.VariableType = e.Term.VariableType;
|
|
||||||
};
|
|
||||||
|
|
||||||
simpleExpression.OnAddGenerator += (_, e) =>
|
simpleExpression.OnAddGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
if (PascalType.IsCalculatable(e.Left.VariableType) && PascalType.IsCalculatable(e.Right.VariableType))
|
simpleExpression.VariableType = e.Left.VariableType + e.Right.VariableType;
|
||||||
{
|
|
||||||
simpleExpression.VariableType = e.Left.VariableType + e.Right.VariableType;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IsError = true;
|
if (simpleExpression.VariableType == PascalBasicType.Void)
|
||||||
logger?.LogError("Can't calculate");
|
{
|
||||||
|
IsError = true;
|
||||||
|
logger?.LogError("Can't calculate");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,10 +180,7 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
expression.VariableType = e.SimpleExpression.VariableType;
|
expression.VariableType = e.SimpleExpression.VariableType;
|
||||||
};
|
};
|
||||||
|
|
||||||
expression.OnRelationGenerator += (_, _) =>
|
expression.OnRelationGenerator += (_, _) => { expression.VariableType = PascalBasicType.Boolean; };
|
||||||
{
|
|
||||||
expression.VariableType = PascalBasicType.Boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostVisit(TypeSyntaxNode typeSyntaxNode)
|
public override void PostVisit(TypeSyntaxNode typeSyntaxNode)
|
||||||
|
@ -251,7 +222,12 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
{
|
{
|
||||||
base.PostVisit(identifierList);
|
base.PostVisit(identifierList);
|
||||||
|
|
||||||
identifierList.OnTypeGenerator += (_, e) => { identifierList.DefinitionType = e.TypeSyntaxNode.PascalType; };
|
identifierList.OnTypeGenerator += (_, e) =>
|
||||||
|
{
|
||||||
|
identifierList.DefinitionType = identifierList.IsReference
|
||||||
|
? e.TypeSyntaxNode.PascalType.ToReferenceType()
|
||||||
|
: e.TypeSyntaxNode.PascalType;
|
||||||
|
};
|
||||||
|
|
||||||
identifierList.OnIdentifierGenerator += (_, e) =>
|
identifierList.OnIdentifierGenerator += (_, e) =>
|
||||||
{
|
{
|
||||||
|
@ -259,9 +235,7 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
|
|
||||||
Symbol symbol = new()
|
Symbol symbol = new()
|
||||||
{
|
{
|
||||||
SymbolName = e.IdentifierToken.IdentifierName,
|
SymbolName = e.IdentifierToken.IdentifierName, SymbolType = identifierList.DefinitionType,
|
||||||
SymbolType = identifierList.DefinitionType,
|
|
||||||
Reference = identifierList.IsReference
|
|
||||||
};
|
};
|
||||||
SymbolTable.TryAddSymbol(symbol);
|
SymbolTable.TryAddSymbol(symbol);
|
||||||
|
|
||||||
|
@ -342,7 +316,7 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
{
|
{
|
||||||
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
||||||
{
|
{
|
||||||
parameters.Add(new PascalParameterType(symbol.SymbolType, symbol.Reference, symbol.SymbolName));
|
parameters.Add(new PascalParameterType(symbol.SymbolType, symbol.SymbolName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,8 +372,7 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
|
||||||
Symbol symbol = new()
|
Symbol symbol = new()
|
||||||
{
|
{
|
||||||
SymbolName = valueParameter.Token.IdentifierName,
|
SymbolName = valueParameter.Token.IdentifierName,
|
||||||
SymbolType = valueParameter.IdentifierList.DefinitionType,
|
SymbolType = valueParameter.IdentifierList.DefinitionType
|
||||||
Reference = valueParameter.IsReference
|
|
||||||
};
|
};
|
||||||
SymbolTable.TryAddSymbol(symbol);
|
SymbolTable.TryAddSymbol(symbol);
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否为定义引用变量
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReference { get; set; }
|
||||||
|
|
||||||
public static TypeSyntaxNode Create(List<SyntaxNodeBase> children)
|
public static TypeSyntaxNode Create(List<SyntaxNodeBase> children)
|
||||||
{
|
{
|
||||||
return new TypeSyntaxNode { Children = children };
|
return new TypeSyntaxNode { Children = children };
|
||||||
|
|
|
@ -36,14 +36,14 @@ public class PascalTypeTests
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PascalFunctionTypeTests()
|
public void PascalFunctionTypeTests()
|
||||||
{
|
{
|
||||||
PascalType function1 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Integer, false, "a")],
|
PascalType function1 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Integer, "a")],
|
||||||
PascalBasicType.Void);
|
PascalBasicType.Void);
|
||||||
PascalType function2 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Integer, false, "a")],
|
PascalType function2 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Integer, "a")],
|
||||||
PascalBasicType.Void);
|
PascalBasicType.Void);
|
||||||
|
|
||||||
Assert.Equal(function1, function2);
|
Assert.Equal(function1, function2);
|
||||||
|
|
||||||
PascalType function3 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Real, true, "a")],
|
PascalType function3 = new PascalFunctionType([new PascalParameterType(PascalBasicType.Real, "a")],
|
||||||
PascalBasicType.Integer);
|
PascalBasicType.Integer);
|
||||||
Assert.NotEqual(function1, function3);
|
Assert.NotEqual(function1, function3);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,13 @@ public class SymbolTableTests
|
||||||
{
|
{
|
||||||
SymbolTable table = new();
|
SymbolTable table = new();
|
||||||
|
|
||||||
Assert.True(table.TryGetType("integer", out PascalType? integer));
|
Assert.True(table.TryGetType("Integer", out PascalType? integer));
|
||||||
Assert.Equal(PascalBasicType.Integer, integer);
|
Assert.Equal(PascalBasicType.Integer, integer);
|
||||||
Assert.True(table.TryGetType("real", out PascalType? real));
|
Assert.True(table.TryGetType("Real", out PascalType? real));
|
||||||
Assert.Equal(PascalBasicType.Real, real);
|
Assert.Equal(PascalBasicType.Real, real);
|
||||||
Assert.True(table.TryGetType("boolean", out PascalType? boolean));
|
Assert.True(table.TryGetType("Boolean", out PascalType? boolean));
|
||||||
Assert.Equal(PascalBasicType.Boolean, boolean);
|
Assert.Equal(PascalBasicType.Boolean, boolean);
|
||||||
Assert.True(table.TryGetType("char", out PascalType? character));
|
Assert.True(table.TryGetType("Character", out PascalType? character));
|
||||||
Assert.Equal(PascalBasicType.Character, character);
|
Assert.Equal(PascalBasicType.Character, character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,10 +25,7 @@ public class SymbolTableTests
|
||||||
SymbolTable table = new();
|
SymbolTable table = new();
|
||||||
|
|
||||||
Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Integer }));
|
Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Integer }));
|
||||||
Assert.True(table.TryAddSymbol(new Symbol
|
Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "temperature", SymbolType = PascalBasicType.Real }));
|
||||||
{
|
|
||||||
SymbolName = "temperature", SymbolType = PascalBasicType.Real, Const = true
|
|
||||||
}));
|
|
||||||
|
|
||||||
Assert.True(table.TryGetSymbol("a", out Symbol? a));
|
Assert.True(table.TryGetSymbol("a", out Symbol? a));
|
||||||
Assert.Equal(PascalBasicType.Integer, a.SymbolType);
|
Assert.Equal(PascalBasicType.Integer, a.SymbolType);
|
||||||
|
@ -42,18 +39,12 @@ public class SymbolTableTests
|
||||||
SymbolTable table = new();
|
SymbolTable table = new();
|
||||||
|
|
||||||
Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Integer }));
|
Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Integer }));
|
||||||
Assert.True(table.TryAddSymbol(new Symbol
|
Assert.True(table.TryAddSymbol(new Symbol { SymbolName = "temperature", SymbolType = PascalBasicType.Real }));
|
||||||
{
|
|
||||||
SymbolName = "temperature", SymbolType = PascalBasicType.Real, Const = true
|
|
||||||
}));
|
|
||||||
|
|
||||||
SymbolTable child = table.CreateChildTable();
|
SymbolTable child = table.CreateChildTable();
|
||||||
|
|
||||||
Assert.True(child.TryAddSymbol(new Symbol{SymbolName = "a", SymbolType = PascalBasicType.Real}));
|
Assert.True(child.TryAddSymbol(new Symbol { SymbolName = "a", SymbolType = PascalBasicType.Real }));
|
||||||
Assert.True(child.TryAddSymbol(new Symbol
|
Assert.True(child.TryAddSymbol(new Symbol { SymbolName = "level2", SymbolType = PascalBasicType.Boolean }));
|
||||||
{
|
|
||||||
SymbolName = "level2", SymbolType = PascalBasicType.Boolean, Reference = true
|
|
||||||
}));
|
|
||||||
|
|
||||||
Assert.True(child.TryGetSymbol("a", out Symbol? a));
|
Assert.True(child.TryGetSymbol("a", out Symbol? a));
|
||||||
Assert.Equal(PascalBasicType.Real, a.SymbolType);
|
Assert.Equal(PascalBasicType.Real, a.SymbolType);
|
||||||
|
|
|
@ -126,9 +126,9 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a")
|
new PascalParameterType(PascalBasicType.Integer, "a")
|
||||||
], PascalBasicType.Void));
|
], PascalBasicType.Void));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +148,9 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Real, true, "a"),
|
new PascalParameterType(PascalBasicType.Real.ToReferenceType(),"a"),
|
||||||
new PascalParameterType(PascalBasicType.Real, true, "a"),
|
new PascalParameterType(PascalBasicType.Real.ToReferenceType(), "a"),
|
||||||
new PascalParameterType(PascalBasicType.Real, true, "a")
|
new PascalParameterType(PascalBasicType.Real.ToReferenceType(), "a")
|
||||||
], PascalBasicType.Void));
|
], PascalBasicType.Void));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,10 +170,10 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Character, true, "a"),
|
new PascalParameterType(PascalBasicType.Character.ToReferenceType(), "a"),
|
||||||
new PascalParameterType(PascalBasicType.Character, true, "a")
|
new PascalParameterType(PascalBasicType.Character.ToReferenceType(), "a")
|
||||||
], PascalBasicType.Void));
|
], PascalBasicType.Void));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +193,10 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Character, true, "a"),
|
new PascalParameterType(PascalBasicType.Character.ToReferenceType(), "a"),
|
||||||
new PascalParameterType(PascalBasicType.Character, true, "a")
|
new PascalParameterType(PascalBasicType.Character.ToReferenceType(), "a")
|
||||||
], PascalBasicType.Real));
|
], PascalBasicType.Real));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,16 +219,16 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test1", out Symbol? symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test1", out Symbol? symbol));
|
||||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Integer, false, "a"),
|
new PascalParameterType(PascalBasicType.Integer, "a"),
|
||||||
new PascalParameterType(PascalBasicType.Real, true, "a"),
|
new PascalParameterType(PascalBasicType.Real.ToReferenceType(), "a"),
|
||||||
new PascalParameterType(PascalBasicType.Real, true, "a"),
|
new PascalParameterType(PascalBasicType.Real.ToReferenceType(), "a"),
|
||||||
new PascalParameterType(PascalBasicType.Boolean, false, "a")
|
new PascalParameterType(PascalBasicType.Boolean, "a")
|
||||||
], PascalBasicType.Void));
|
], PascalBasicType.Void));
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test2", out symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test2", out symbol));
|
||||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Boolean, true, "a"),
|
new PascalParameterType(PascalBasicType.Boolean.ToReferenceType(), "a"),
|
||||||
new PascalParameterType(PascalBasicType.Boolean, true, "a")
|
new PascalParameterType(PascalBasicType.Boolean.ToReferenceType(), "a")
|
||||||
], PascalBasicType.Boolean));
|
], PascalBasicType.Boolean));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +279,6 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
||||||
Assert.Equal(PascalBasicType.Integer, symbol.SymbolType);
|
Assert.Equal(PascalBasicType.Integer, symbol.SymbolType);
|
||||||
Assert.True(symbol.Const);
|
|
||||||
|
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("b", out symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("b", out symbol));
|
||||||
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
||||||
|
@ -290,7 +289,7 @@ public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out symbol));
|
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out symbol));
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
new PascalFunctionType([
|
new PascalFunctionType([
|
||||||
new PascalParameterType(PascalBasicType.Boolean, false, "a")
|
new PascalParameterType(PascalBasicType.Boolean, "a")
|
||||||
], PascalBasicType.Void), symbol.SymbolType);
|
], PascalBasicType.Void), symbol.SymbolType);
|
||||||
|
|
||||||
Assert.False(visitor.SymbolTable.TryGetSymbol("d", out symbol));
|
Assert.False(visitor.SymbolTable.TryGetSymbol("d", out symbol));
|
||||||
|
|
Loading…
Reference in New Issue
Block a user