parent
b20c3234c5
commit
17dbcccb59
302
Canon.Core/Abstractions/SyntaxNodeVisitor.cs
Normal file
302
Canon.Core/Abstractions/SyntaxNodeVisitor.cs
Normal file
|
@ -0,0 +1,302 @@
|
|||
using Canon.Core.SyntaxNodes;
|
||||
|
||||
namespace Canon.Core.Abstractions;
|
||||
|
||||
public abstract class SyntaxNodeVisitor
|
||||
{
|
||||
public virtual void PreVisit(AddOperator addOperator)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(AddOperator addOperator)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(BasicType basicType)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(BasicType basicType)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(CompoundStatement compoundStatement)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(CompoundStatement compoundStatement)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ConstDeclaration constDeclaration)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ConstDeclaration constDeclaration)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ConstDeclarations constDeclarations)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ConstDeclarations constDeclarations)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ConstValue constValue)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ConstValue constValue)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ElsePart elsePart)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ElsePart elsePart)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Expression expression)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Expression expression)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ExpressionList expressionList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ExpressionList expressionList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Factor factor)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Factor factor)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(FormalParameter formalParameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(FormalParameter formalParameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(IdentifierList identifierList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(IdentifierList identifierList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(IdentifierVarPart identifierVarPart)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(IdentifierVarPart identifierVarPart)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(MultiplyOperator multiplyOperator)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(MultiplyOperator multiplyOperator)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Parameter parameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Parameter parameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ParameterList parameterList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ParameterList parameterList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Period period)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Period period)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ProcedureCall procedureCall)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ProcedureCall procedureCall)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ProgramBody programBody)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ProgramBody programBody)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ProgramHead programHead)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ProgramHead programHead)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ProgramStruct programStruct)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ProgramStruct programStruct)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(RelationOperator relationOperator)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(RelationOperator relationOperator)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(SimpleExpression simpleExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(SimpleExpression simpleExpression)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Statement statement)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Statement statement)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(StatementList statementList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(StatementList statementList)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Subprogram subprogram)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Subprogram subprogram)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(SubprogramBody subprogramBody)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(SubprogramBody subprogramBody)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(SubprogramDeclarations subprogramDeclarations)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(SubprogramDeclarations subprogramDeclarations)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(SubprogramHead subprogramHead)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(SubprogramHead subprogramHead)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Term term)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Term term)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(TypeSyntaxNode typeSyntaxNode)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(TypeSyntaxNode typeSyntaxNode)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(ValueParameter valueParameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(ValueParameter valueParameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(VarDeclaration varDeclaration)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(VarDeclaration varDeclaration)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(VarDeclarations varDeclarations)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(VarDeclarations varDeclarations)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(Variable variable)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(Variable variable)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(VarParameter varParameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(VarParameter varParameter)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PreVisit(TerminatedSyntaxNode terminatedSyntaxNode)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostVisit(TerminatedSyntaxNode terminatedSyntaxNode)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -10,4 +10,8 @@
|
|||
<None Include="../.gitignore" />
|
||||
<None Include="../.editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -160,6 +160,36 @@ public class NumberSemanticToken : SemanticToken
|
|||
|
||||
public required NumberType NumberType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 将数值类型记号识别为整数
|
||||
/// </summary>
|
||||
/// <returns>该记号表示的整数</returns>
|
||||
/// <exception cref="InvalidOperationException">目标记号不是整数类型</exception>
|
||||
public int ParseAsInteger()
|
||||
{
|
||||
if (NumberType != NumberType.Integer)
|
||||
{
|
||||
throw new InvalidOperationException("Target semantic token isn't integer");
|
||||
}
|
||||
|
||||
return int.Parse(LiteralValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将数值类型记号识别为浮点数
|
||||
/// </summary>
|
||||
/// <returns>该记号标识的浮点数</returns>
|
||||
/// <exception cref="InvalidOperationException">目标记号不是浮点数类型</exception>
|
||||
public double ParseAsReal()
|
||||
{
|
||||
if (NumberType != NumberType.Real)
|
||||
{
|
||||
throw new InvalidOperationException("Target semantic token isn't real");
|
||||
}
|
||||
|
||||
return double.Parse(LiteralValue);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode() ^ NumberType.GetHashCode();
|
||||
|
|
17
Canon.Core/SemanticParser/CCodeGenerateVisitor.cs
Normal file
17
Canon.Core/SemanticParser/CCodeGenerateVisitor.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
|
||||
namespace Canon.Core.SemanticParser;
|
||||
|
||||
public class CCodeGenerateVisitor : TypeCheckVisitor
|
||||
{
|
||||
public CCodeBuilder Builder { get; } = new();
|
||||
|
||||
public override void PreVisit(ProgramStruct programStruct)
|
||||
{
|
||||
base.PreVisit(programStruct);
|
||||
|
||||
Builder.AddString("#include <stdbool.h>\n");
|
||||
Builder.AddString("#include <stdio.h>\n");
|
||||
}
|
||||
}
|
|
@ -44,4 +44,31 @@ public abstract class PascalType : IEquatable<PascalType>
|
|||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
public static PascalType operator +(PascalType a, PascalType b)
|
||||
{
|
||||
if (!IsCalculatable(a) || !IsCalculatable(b))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (a == PascalBasicType.Integer && b == PascalBasicType.Integer)
|
||||
{
|
||||
return PascalBasicType.Integer;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PascalBasicType.Real;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为可计算的类型
|
||||
/// </summary>
|
||||
/// <param name="pascalType">需要判断的Pascal类型</param>
|
||||
/// <returns>是否为可计算的类型</returns>
|
||||
public static bool IsCalculatable(PascalType pascalType)
|
||||
{
|
||||
return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,23 @@ public class SymbolTable
|
|||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获得父符号表
|
||||
/// </summary>
|
||||
/// <param name="parent">获得的父符号表</param>
|
||||
/// <returns>是否存在父符号表</returns>
|
||||
public bool TryGetParent([NotNullWhen(true)] out SymbolTable? parent)
|
||||
{
|
||||
if (_parent is null)
|
||||
{
|
||||
parent = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
parent = _parent;
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<SymbolTable> GetParents()
|
||||
{
|
||||
SymbolTable? now = _parent;
|
||||
|
|
55
Canon.Core/SemanticParser/SyntaxTreeTraveller.cs
Normal file
55
Canon.Core/SemanticParser/SyntaxTreeTraveller.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
|
||||
namespace Canon.Core.SemanticParser;
|
||||
|
||||
public class SyntaxTreeTraveller
|
||||
{
|
||||
private readonly Stack<SyntaxNodeBase> _stack = [];
|
||||
private readonly HashSet<SyntaxNodeBase> _visited = [];
|
||||
|
||||
public void Travel(ProgramStruct root, SyntaxNodeVisitor visitor)
|
||||
{
|
||||
_stack.Clear();
|
||||
_visited.Clear();
|
||||
_stack.Push(root);
|
||||
|
||||
while (_stack.Count != 0)
|
||||
{
|
||||
SyntaxNodeBase node = _stack.Peek();
|
||||
if (!_visited.Contains(node))
|
||||
{
|
||||
node.PreVisit(visitor);
|
||||
}
|
||||
|
||||
if (node.IsTerminated)
|
||||
{
|
||||
node.PostVisit(visitor);
|
||||
_stack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
NonTerminatedSyntaxNode nonTerminatedNode = node.Convert<NonTerminatedSyntaxNode>();
|
||||
|
||||
if (nonTerminatedNode.Children.Count == 0)
|
||||
{
|
||||
node.PostVisit(visitor);
|
||||
_stack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_visited.Contains(nonTerminatedNode))
|
||||
{
|
||||
node.PostVisit(visitor);
|
||||
_stack.Pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
_visited.Add(nonTerminatedNode);
|
||||
foreach (SyntaxNodeBase child in nonTerminatedNode.Children.AsEnumerable().Reverse())
|
||||
{
|
||||
_stack.Push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
374
Canon.Core/SemanticParser/TypeCheckVisitor.cs
Normal file
374
Canon.Core/SemanticParser/TypeCheckVisitor.cs
Normal file
|
@ -0,0 +1,374 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Canon.Core.SemanticParser;
|
||||
|
||||
public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : SyntaxNodeVisitor
|
||||
{
|
||||
public SymbolTable SymbolTable { get; private set; } = new();
|
||||
|
||||
public override void PostVisit(ConstValue constValue)
|
||||
{
|
||||
base.PostVisit(constValue);
|
||||
constValue.OnNumberGenerator += (_, e) =>
|
||||
{
|
||||
switch (e.Token.NumberType)
|
||||
{
|
||||
case NumberType.Integer:
|
||||
constValue.ConstType = PascalBasicType.Integer;
|
||||
break;
|
||||
case NumberType.Real:
|
||||
constValue.ConstType = PascalBasicType.Real;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
constValue.OnCharacterGenerator += (_, _) => { constValue.ConstType = PascalBasicType.Character; };
|
||||
}
|
||||
|
||||
public override void PostVisit(ConstDeclaration constDeclaration)
|
||||
{
|
||||
base.PostVisit(constDeclaration);
|
||||
(IdentifierSemanticToken token, ConstValue constValue) = constDeclaration.ConstValue;
|
||||
|
||||
bool result = SymbolTable.TryAddSymbol(new Symbol
|
||||
{
|
||||
Const = true, SymbolName = token.IdentifierName, SymbolType = constValue.ConstType
|
||||
});
|
||||
|
||||
if (!result)
|
||||
{
|
||||
logger?.LogError("Identifier '{}' has been declared twice!", token.IdentifierName);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostVisit(Factor factor)
|
||||
{
|
||||
base.PostVisit(factor);
|
||||
|
||||
// factor -> num
|
||||
factor.OnNumberGenerator += (_, e) =>
|
||||
{
|
||||
switch (e.Token.NumberType)
|
||||
{
|
||||
case NumberType.Integer:
|
||||
factor.FactorType = PascalBasicType.Integer;
|
||||
break;
|
||||
case NumberType.Real:
|
||||
factor.FactorType = PascalBasicType.Real;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// factor -> variable
|
||||
factor.OnVariableGenerator += (_, e) =>
|
||||
{
|
||||
if (SymbolTable.TryGetSymbol(e.Variable.Identifier.IdentifierName, out Symbol? symbol))
|
||||
{
|
||||
factor.FactorType = symbol.SymbolType;
|
||||
}
|
||||
};
|
||||
|
||||
// factor -> (expression)
|
||||
factor.OnParethnesisGenerator += (_, e) => { factor.FactorType = e.Expression.ExprssionType; };
|
||||
|
||||
// factor -> id (expression_list)
|
||||
factor.OnProcedureCallGenerator += (_, e) =>
|
||||
{
|
||||
if (!SymbolTable.TryGetSymbol(e.ProcedureName.IdentifierName, out Symbol? procedure))
|
||||
{
|
||||
logger?.LogError("Procedure '{}' does not define.", e.ProcedureName.IdentifierName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (procedure.SymbolType is not PascalFunctionType functionType)
|
||||
{
|
||||
logger?.LogError("Identifier '{}' is not a call-able.", procedure.SymbolName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (functionType.ReturnType == PascalBasicType.Void)
|
||||
{
|
||||
logger?.LogError("Procedure '{}' returns void.", procedure.SymbolName);
|
||||
return;
|
||||
}
|
||||
|
||||
factor.FactorType = functionType.ReturnType;
|
||||
|
||||
if (e.Parameters.Expressions.Count != functionType.Parameters.Count)
|
||||
{
|
||||
logger?.LogError("Procedure '{}' expects {} parameters but {} provided.",
|
||||
procedure.SymbolName,
|
||||
functionType.Parameters.Count,
|
||||
e.Parameters.Expressions.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ((Expression expression, PascalParameterType parameterType) in e.Parameters.Expressions.Zip(
|
||||
functionType.Parameters))
|
||||
{
|
||||
if (expression.ExprssionType != parameterType)
|
||||
{
|
||||
logger?.LogError("");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// factor -> factor
|
||||
factor.OnNotGenerator += (_, e) =>
|
||||
{
|
||||
if (e.Factor.FactorType != PascalBasicType.Boolean)
|
||||
{
|
||||
logger?.LogError("The boolean type is expected.");
|
||||
return;
|
||||
}
|
||||
|
||||
factor.FactorType = PascalBasicType.Boolean;
|
||||
};
|
||||
|
||||
// factor -> uminus factor
|
||||
factor.OnUminusGenerator += (_, e) => { factor.FactorType = e.Factor.FactorType; };
|
||||
}
|
||||
|
||||
public override void PostVisit(Term term)
|
||||
{
|
||||
base.PostVisit(term);
|
||||
|
||||
term.OnFactorGenerator += (_, e) => { term.TermType = e.Factor.FactorType; };
|
||||
|
||||
term.OnMultiplyGenerator += (_, e) =>
|
||||
{
|
||||
if (PascalType.IsCalculatable(e.Left.TermType) && PascalType.IsCalculatable(e.Right.FactorType))
|
||||
{
|
||||
term.TermType = e.Left.TermType + e.Right.FactorType;
|
||||
return;
|
||||
}
|
||||
|
||||
logger?.LogError("Can't calculate");
|
||||
};
|
||||
}
|
||||
|
||||
public override void PostVisit(SimpleExpression simpleExpression)
|
||||
{
|
||||
base.PostVisit(simpleExpression);
|
||||
|
||||
simpleExpression.OnTermGenerator += (_, e) => { simpleExpression.SimpleExpressionType = e.Term.TermType; };
|
||||
|
||||
simpleExpression.OnAddGenerator += (_, e) =>
|
||||
{
|
||||
if (PascalType.IsCalculatable(e.Left.SimpleExpressionType) && PascalType.IsCalculatable(e.Right.TermType))
|
||||
{
|
||||
simpleExpression.SimpleExpressionType = e.Left.SimpleExpressionType + e.Right.TermType;
|
||||
return;
|
||||
}
|
||||
|
||||
logger?.LogError("Can't calculate");
|
||||
};
|
||||
}
|
||||
|
||||
public override void PostVisit(Expression expression)
|
||||
{
|
||||
base.PostVisit(expression);
|
||||
|
||||
expression.OnSimpleExpressionGenerator += (_, e) =>
|
||||
{
|
||||
expression.ExprssionType = e.SimpleExpression.SimpleExpressionType;
|
||||
};
|
||||
|
||||
expression.OnRelationGenerator += (_, _) => { expression.ExprssionType = PascalBasicType.Boolean; };
|
||||
}
|
||||
|
||||
public override void PostVisit(TypeSyntaxNode typeSyntaxNode)
|
||||
{
|
||||
base.PostVisit(typeSyntaxNode);
|
||||
|
||||
typeSyntaxNode.OnBasicTypeGenerator += (_, e) => { typeSyntaxNode.PascalType = e.BasicType.PascalType; };
|
||||
|
||||
typeSyntaxNode.OnArrayTypeGenerator += (_, e) =>
|
||||
{
|
||||
List<Period> periods = e.Period.Periods;
|
||||
(NumberSemanticToken begin, NumberSemanticToken end) = periods.Last().Range;
|
||||
|
||||
PascalType arrayType =
|
||||
new PascalArrayType(e.BasicType.PascalType, begin.ParseAsInteger(), end.ParseAsInteger());
|
||||
|
||||
for (int i = periods.Count - 2; i >= 0; i--)
|
||||
{
|
||||
(begin, end) = periods[i].Range;
|
||||
arrayType = new PascalArrayType(arrayType, begin.ParseAsInteger(), end.ParseAsInteger());
|
||||
}
|
||||
|
||||
typeSyntaxNode.PascalType = arrayType;
|
||||
};
|
||||
}
|
||||
|
||||
public override void PreVisit(IdentifierList identifierList)
|
||||
{
|
||||
base.PreVisit(identifierList);
|
||||
|
||||
identifierList.OnIdentifierGenerator += (_, e) =>
|
||||
{
|
||||
e.IdentifierList.IsReference = identifierList.IsReference;
|
||||
e.IdentifierList.IsProcedure = identifierList.IsProcedure;
|
||||
};
|
||||
}
|
||||
|
||||
public override void PostVisit(IdentifierList identifierList)
|
||||
{
|
||||
base.PostVisit(identifierList);
|
||||
|
||||
identifierList.OnTypeGenerator += (_, e) => { identifierList.DefinitionType = e.TypeSyntaxNode.PascalType; };
|
||||
|
||||
identifierList.OnIdentifierGenerator += (_, e) =>
|
||||
{
|
||||
identifierList.DefinitionType = e.IdentifierList.DefinitionType;
|
||||
|
||||
Symbol symbol = new()
|
||||
{
|
||||
SymbolName = e.IdentifierToken.IdentifierName,
|
||||
SymbolType = identifierList.DefinitionType,
|
||||
Reference = identifierList.IsReference
|
||||
|
||||
};
|
||||
SymbolTable.TryAddSymbol(symbol);
|
||||
|
||||
if (identifierList.IsProcedure)
|
||||
{
|
||||
_parameters!.Add(symbol);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override void PostVisit(VarDeclaration varDeclaration)
|
||||
{
|
||||
base.PostVisit(varDeclaration);
|
||||
|
||||
SymbolTable.TryAddSymbol(new Symbol
|
||||
{
|
||||
SymbolName = varDeclaration.Token.IdentifierName,
|
||||
SymbolType = varDeclaration.IdentifierList.DefinitionType
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 存储定义函数过程中的参数列表
|
||||
/// 考虑到不同的ValueParameter
|
||||
/// ValueParameter的顺序是正确的
|
||||
/// 但ValueParameter中的顺序是相反的
|
||||
/// 因此设置二维数组存储
|
||||
/// </summary>
|
||||
private List<Symbol>? _parameters;
|
||||
|
||||
/// <summary>
|
||||
/// 多个ValueParameter下定义的参数列表
|
||||
/// </summary>
|
||||
private readonly List<List<Symbol>> _valueParameters = [];
|
||||
|
||||
public override void PreVisit(Subprogram subprogram)
|
||||
{
|
||||
base.PreVisit(subprogram);
|
||||
|
||||
SymbolTable = SymbolTable.CreateChildTable();
|
||||
}
|
||||
|
||||
public override void PostVisit(Subprogram subprogram)
|
||||
{
|
||||
base.PostVisit(subprogram);
|
||||
|
||||
if (!SymbolTable.TryGetParent(out SymbolTable? parent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SymbolTable = parent;
|
||||
}
|
||||
|
||||
public override void PreVisit(SubprogramHead subprogramHead)
|
||||
{
|
||||
base.PreVisit(subprogramHead);
|
||||
|
||||
_parameters = null;
|
||||
_valueParameters.Clear();
|
||||
}
|
||||
|
||||
public override void PostVisit(SubprogramHead subprogramHead)
|
||||
{
|
||||
base.PostVisit(subprogramHead);
|
||||
|
||||
// 将当前过程的符号添加到父符号表中
|
||||
if (!SymbolTable.TryGetParent(out SymbolTable? parent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<PascalParameterType> parameters = [];
|
||||
|
||||
// 正序遍历_valueParameter
|
||||
// 倒序遍历其中的列表
|
||||
foreach (List<Symbol> children in _valueParameters)
|
||||
{
|
||||
foreach (Symbol symbol in children.AsEnumerable().Reverse())
|
||||
{
|
||||
parameters.Add(new PascalParameterType(symbol.SymbolType, symbol.Reference));
|
||||
}
|
||||
}
|
||||
|
||||
subprogramHead.OnProcedureGenerator += (_, _) =>
|
||||
{
|
||||
parent.TryAddSymbol(new Symbol
|
||||
{
|
||||
SymbolName = subprogramHead.SubprogramName.IdentifierName,
|
||||
SymbolType = new PascalFunctionType(parameters, PascalBasicType.Void)
|
||||
});
|
||||
};
|
||||
|
||||
subprogramHead.OnFunctionGenerator += (_, e) =>
|
||||
{
|
||||
parent.TryAddSymbol(new Symbol
|
||||
{
|
||||
SymbolName = subprogramHead.SubprogramName.IdentifierName,
|
||||
SymbolType = new PascalFunctionType(parameters, e.ReturnType.PascalType)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public override void PreVisit(VarParameter varParameter)
|
||||
{
|
||||
base.PreVisit(varParameter);
|
||||
|
||||
varParameter.ValueParameter.IsReference = true;
|
||||
}
|
||||
|
||||
public override void PreVisit(ValueParameter valueParameter)
|
||||
{
|
||||
base.PreVisit(valueParameter);
|
||||
|
||||
valueParameter.IdentifierList.IsProcedure = true;
|
||||
_parameters = [];
|
||||
_valueParameters.Add(_parameters);
|
||||
if (valueParameter.IsReference)
|
||||
{
|
||||
valueParameter.IdentifierList.IsReference = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostVisit(ValueParameter valueParameter)
|
||||
{
|
||||
base.PostVisit(valueParameter);
|
||||
|
||||
Symbol symbol = new()
|
||||
{
|
||||
SymbolName = valueParameter.Token.IdentifierName,
|
||||
SymbolType = valueParameter.IdentifierList.DefinitionType,
|
||||
Reference = valueParameter.IsReference
|
||||
};
|
||||
SymbolTable.TryAddSymbol(symbol);
|
||||
|
||||
// 同时添加到参数列表
|
||||
_parameters!.Add(symbol);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
|
@ -33,4 +34,14 @@ public class AddOperator : NonTerminatedSyntaxNode
|
|||
builder.AddString(" ||");
|
||||
}
|
||||
}
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
@ -9,9 +10,31 @@ public class BasicType : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.BasicType;
|
||||
|
||||
public static BasicType Create(List<SyntaxNodeBase> children)
|
||||
/// <summary>
|
||||
/// BasicType代表的Pascal类型
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public PascalType PascalType
|
||||
{
|
||||
return new BasicType { Children = children };
|
||||
get
|
||||
{
|
||||
KeywordType keywordType = Children[0].Convert<TerminatedSyntaxNode>().Token
|
||||
.Convert<KeywordSemanticToken>().KeywordType;
|
||||
|
||||
switch (keywordType)
|
||||
{
|
||||
case KeywordType.Integer:
|
||||
return PascalBasicType.Integer;
|
||||
case KeywordType.Real:
|
||||
return PascalBasicType.Real;
|
||||
case KeywordType.Character:
|
||||
return PascalBasicType.Character;
|
||||
case KeywordType.Boolean:
|
||||
return PascalBasicType.Boolean;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
|
@ -36,27 +59,18 @@ public class BasicType : NonTerminatedSyntaxNode
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///尝试获取Pascal的基本类型
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public PascalType TryGetPascalType()
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
var keywordType = Children[0].Convert<TerminatedSyntaxNode>().Token
|
||||
.Convert<KeywordSemanticToken>().KeywordType;
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
switch (keywordType)
|
||||
{
|
||||
case KeywordType.Integer:
|
||||
return PascalBasicType.Integer;
|
||||
case KeywordType.Real:
|
||||
return PascalBasicType.Real;
|
||||
case KeywordType.Boolean:
|
||||
return PascalBasicType.Boolean;
|
||||
case KeywordType.Character:
|
||||
return PascalBasicType.Character;
|
||||
}
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
return PascalBasicType.Void;
|
||||
public static BasicType Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new BasicType { Children = children };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -9,6 +10,16 @@ public class CompoundStatement : NonTerminatedSyntaxNode
|
|||
|
||||
public IEnumerable<Statement> Statements => Children[1].Convert<StatementList>().Statements;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static CompoundStatement Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new CompoundStatement { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -17,6 +18,16 @@ public class ConstDeclaration : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public (IdentifierSemanticToken, ConstValue) ConstValue => GetConstValue();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ConstDeclaration Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
bool isRecursive;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
|
@ -13,6 +14,16 @@ public class ConstDeclarations : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public IEnumerable<(IdentifierSemanticToken, ConstValue)> ConstValues => GetConstValues();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ConstDeclarations Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ConstDeclarations { Children = children };
|
||||
|
|
|
@ -1,12 +1,127 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
/// <summary>
|
||||
/// 使用数值产生式事件的事件参数
|
||||
/// </summary>
|
||||
public class NumberConstValueEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否含有负号
|
||||
/// </summary>
|
||||
public bool IsNegative { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 数值记号
|
||||
/// </summary>
|
||||
public required NumberSemanticToken Token { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用字符产生式事件的事件参数
|
||||
/// </summary>
|
||||
public class CharacterConstValueEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 字符记号
|
||||
/// </summary>
|
||||
public required CharacterSemanticToken Token { get; init; }
|
||||
}
|
||||
|
||||
public class ConstValue : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.ConstValue;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseGeneratorEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseGeneratorEvent();
|
||||
}
|
||||
|
||||
private PascalType? _constType;
|
||||
|
||||
/// <summary>
|
||||
/// 该ConstValue代表的类型
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">尚未分析该类型</exception>
|
||||
public PascalType ConstType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_constType is null)
|
||||
{
|
||||
throw new InvalidOperationException("ConstType has not been set");
|
||||
}
|
||||
|
||||
return _constType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_constType = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用数值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<NumberConstValueEventArgs>? OnNumberGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用字符产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<CharacterConstValueEventArgs>? OnCharacterGenerator;
|
||||
|
||||
private void RaiseGeneratorEvent()
|
||||
{
|
||||
if (Children.Count == 2)
|
||||
{
|
||||
OperatorSemanticToken operatorSemanticToken = Children[0].Convert<TerminatedSyntaxNode>().Token
|
||||
.Convert<OperatorSemanticToken>();
|
||||
NumberSemanticToken numberSemanticToken = Children[1].Convert<TerminatedSyntaxNode>().Token
|
||||
.Convert<NumberSemanticToken>();
|
||||
|
||||
OnNumberGenerator?.Invoke(this, new NumberConstValueEventArgs
|
||||
{
|
||||
Token = numberSemanticToken,
|
||||
IsNegative = operatorSemanticToken.OperatorType == OperatorType.Minus
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
|
||||
if (token.TokenType == SemanticTokenType.Number)
|
||||
{
|
||||
OnNumberGenerator?.Invoke(this,
|
||||
new NumberConstValueEventArgs
|
||||
{
|
||||
Token = token.Convert<NumberSemanticToken>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnCharacterGenerator?.Invoke(this, new CharacterConstValueEventArgs
|
||||
{
|
||||
Token = token.Convert<CharacterSemanticToken>()
|
||||
});
|
||||
}
|
||||
|
||||
OnNumberGenerator = null;
|
||||
OnCharacterGenerator = null;
|
||||
}
|
||||
|
||||
public static ConstValue Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ConstValue { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -7,6 +8,16 @@ public class ElsePart : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.ElsePart;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ElsePart Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ElsePart { Children = children };
|
||||
|
|
|
@ -1,17 +1,97 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnSimpleExpressionGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required SimpleExpression SimpleExpression { get; init; }
|
||||
}
|
||||
|
||||
public class OnRelationGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required SimpleExpression Left { get; init; }
|
||||
|
||||
public required RelationOperator Operator { get; init; }
|
||||
|
||||
public required SimpleExpression Right { get; init; }
|
||||
}
|
||||
|
||||
public class Expression : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.Expression;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnSimpleExpressionGeneratorEventArgs>? OnSimpleExpressionGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 关系产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnRelationGeneratorEventArgs>? OnRelationGenerator;
|
||||
|
||||
private PascalType? _expressionType;
|
||||
|
||||
public PascalType ExprssionType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_expressionType is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _expressionType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_expressionType = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static Expression Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new Expression { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnSimpleExpressionGenerator?.Invoke(this, new OnSimpleExpressionGeneratorEventArgs
|
||||
{
|
||||
SimpleExpression = Children[0].Convert<SimpleExpression>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnRelationGenerator?.Invoke(this, new OnRelationGeneratorEventArgs
|
||||
{
|
||||
Left = Children[0].Convert<SimpleExpression>(),
|
||||
Operator = Children[1].Convert<RelationOperator>(),
|
||||
Right = Children[2].Convert<SimpleExpression>()
|
||||
});
|
||||
}
|
||||
|
||||
OnSimpleExpressionGenerator = null;
|
||||
OnRelationGenerator = null;
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -7,67 +7,39 @@ public class ExpressionList : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.ExpressionList;
|
||||
|
||||
public bool IsRecursive { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// 声明的表达式列表
|
||||
/// 子表达式列表
|
||||
/// </summary>
|
||||
public IEnumerable<Expression> Expressions => GetExpressions();
|
||||
public List<Expression> Expressions { get; } = [];
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ExpressionList Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
bool isRecursive;
|
||||
ExpressionList result = new() { Children = children };
|
||||
|
||||
if (children.Count == 1)
|
||||
{
|
||||
isRecursive = false;
|
||||
result.Expressions.Add(children[0].Convert<Expression>());
|
||||
}
|
||||
else if (children.Count == 3)
|
||||
{
|
||||
isRecursive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return new ExpressionList { Children = children, IsRecursive = isRecursive };
|
||||
}
|
||||
|
||||
private IEnumerable<Expression> GetExpressions()
|
||||
{
|
||||
ExpressionList list = this;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (list.IsRecursive)
|
||||
foreach (Expression expression in children[0].Convert<ExpressionList>().Expressions)
|
||||
{
|
||||
yield return list.Children[2].Convert<Expression>();
|
||||
list = list.Children[0].Convert<ExpressionList>();
|
||||
result.Expressions.Add(expression);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return list.Children[0].Convert<Expression>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
//用逗号分隔输出的expression
|
||||
using var enumerator = Expressions.GetEnumerator();
|
||||
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
enumerator.Current.GenerateCCode(builder);
|
||||
}
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
builder.AddString(", ");
|
||||
enumerator.Current.GenerateCCode(builder);
|
||||
result.Expressions.Add(children[2].Convert<Expression>());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,173 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnNumberGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required NumberSemanticToken Token { get; init; }
|
||||
}
|
||||
|
||||
public class OnVariableGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Variable Variable { get; init; }
|
||||
}
|
||||
|
||||
public class OnParethnesisGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Expression Expression { get; init; }
|
||||
}
|
||||
|
||||
public class OnProcedureCallGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken ProcedureName { get; init; }
|
||||
|
||||
public required ExpressionList Parameters { get; init; }
|
||||
}
|
||||
|
||||
public class OnNotGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Factor Factor { get; init; }
|
||||
}
|
||||
|
||||
public class OnUminusGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Factor Factor { get; init; }
|
||||
}
|
||||
|
||||
public class Factor : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.Factor;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用数值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnNumberGeneratorEventArgs>? OnNumberGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用括号产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnParethnesisGeneratorEventArgs>? OnParethnesisGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用变量产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnVariableGeneratorEventArgs>? OnVariableGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用过程调用产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnProcedureCallGeneratorEventArgs>? OnProcedureCallGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用否定产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnNotGeneratorEventArgs>? OnNotGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用负号产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnUminusGeneratorEventArgs>? OnUminusGenerator;
|
||||
|
||||
private PascalType? _factorType;
|
||||
|
||||
public PascalType FactorType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_factorType is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _factorType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_factorType = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static Factor Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new Factor { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
//factor -> num
|
||||
if (Children[0].IsTerminated)
|
||||
{
|
||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
OnNumberGenerator?.Invoke(this,
|
||||
new OnNumberGeneratorEventArgs { Token = token.Convert<NumberSemanticToken>() });
|
||||
}
|
||||
// factor -> variable
|
||||
else
|
||||
{
|
||||
OnVariableGenerator?.Invoke(this,
|
||||
new OnVariableGeneratorEventArgs { Variable = Children[0].Convert<Variable>() });
|
||||
}
|
||||
}
|
||||
//factor -> ( expression )
|
||||
else if (Children.Count == 3)
|
||||
{
|
||||
OnParethnesisGenerator?.Invoke(this,
|
||||
new OnParethnesisGeneratorEventArgs { Expression = Children[1].Convert<Expression>() });
|
||||
}
|
||||
//factor -> id ( expression )
|
||||
else if (Children.Count == 4)
|
||||
{
|
||||
OnProcedureCallGenerator?.Invoke(this,
|
||||
new OnProcedureCallGeneratorEventArgs
|
||||
{
|
||||
ProcedureName =
|
||||
Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
Parameters = Children[2].Convert<ExpressionList>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SemanticToken token = Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
Factor factor = Children[1].Convert<Factor>();
|
||||
|
||||
if (token.TokenType == SemanticTokenType.Keyword)
|
||||
{
|
||||
// factor -> not factor
|
||||
OnNotGenerator?.Invoke(this, new OnNotGeneratorEventArgs { Factor = factor });
|
||||
}
|
||||
else
|
||||
{
|
||||
// factor -> uminus factor
|
||||
OnUminusGenerator?.Invoke(this, new OnUminusGeneratorEventArgs { Factor = factor });
|
||||
}
|
||||
}
|
||||
|
||||
OnNumberGenerator = null;
|
||||
OnVariableGenerator = null;
|
||||
OnParethnesisGenerator = null;
|
||||
OnProcedureCallGenerator = null;
|
||||
OnNotGenerator = null;
|
||||
OnUminusGenerator = null;
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
if (Children.Count == 1)
|
||||
|
@ -42,14 +197,15 @@ public class Factor : NonTerminatedSyntaxNode
|
|||
//factor -> id ( expression )
|
||||
else if (Children.Count == 4)
|
||||
{
|
||||
builder.AddString(" " + Children[0].Convert<TerminatedSyntaxNode>().Token.
|
||||
Convert<IdentifierSemanticToken>().IdentifierName);
|
||||
builder.AddString(" " + Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>()
|
||||
.IdentifierName);
|
||||
builder.AddString("(");
|
||||
Children[2].GenerateCCode(builder);
|
||||
builder.AddString(")");
|
||||
}
|
||||
else
|
||||
{ //factor -> not factor
|
||||
{
|
||||
//factor -> not factor
|
||||
builder.AddString(" (");
|
||||
if (Children[0].Convert<TerminatedSyntaxNode>().Token.TokenType == SemanticTokenType.Keyword)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -6,26 +7,18 @@ public class FormalParameter : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.FormalParameter;
|
||||
|
||||
/// <summary>
|
||||
/// 声明的参数列表
|
||||
/// </summary>
|
||||
public IEnumerable<Parameter> Parameters => GetParameters();
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static FormalParameter Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new FormalParameter { Children = children };
|
||||
}
|
||||
|
||||
private IEnumerable<Parameter> GetParameters()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (Parameter parameter in Children[1].Convert<ParameterList>().Parameters)
|
||||
{
|
||||
yield return parameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,75 +1,97 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnIdentifierGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken IdentifierToken { get; init; }
|
||||
|
||||
public required IdentifierList IdentifierList { get; init; }
|
||||
}
|
||||
|
||||
public class OnTypeGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required TypeSyntaxNode TypeSyntaxNode { get; init; }
|
||||
}
|
||||
|
||||
public class IdentifierList : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.IdentifierList;
|
||||
|
||||
/// <summary>
|
||||
/// 是否含有递归定义
|
||||
/// </summary>
|
||||
public bool IsRecursive { get; private init; }
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
private PascalType? _definitionType;
|
||||
|
||||
/// <summary>
|
||||
/// 声明的标识符列表
|
||||
/// IdentifierList中定义的类型
|
||||
/// </summary>
|
||||
public IEnumerable<IdentifierSemanticToken> Identifiers => GetIdentifiers();
|
||||
/// <exception cref="InvalidOperationException">尚未确定定义的类型</exception>
|
||||
public PascalType DefinitionType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_definitionType is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _definitionType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_definitionType = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否为参数中的引用参数
|
||||
/// </summary>
|
||||
public bool IsReference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否在过程定义中使用
|
||||
/// </summary>
|
||||
public bool IsProcedure { get; set; }
|
||||
|
||||
public event EventHandler<OnIdentifierGeneratorEventArgs>? OnIdentifierGenerator;
|
||||
|
||||
public event EventHandler<OnTypeGeneratorEventArgs>? OnTypeGenerator;
|
||||
|
||||
public static IdentifierList Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
bool isRecursive;
|
||||
return new IdentifierList { Children = children };
|
||||
}
|
||||
|
||||
if (children.Count == 2)
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 2)
|
||||
{
|
||||
isRecursive = false;
|
||||
}
|
||||
else if (children.Count == 3)
|
||||
{
|
||||
isRecursive = true;
|
||||
OnTypeGenerator?.Invoke(this,
|
||||
new OnTypeGeneratorEventArgs { TypeSyntaxNode = Children[1].Convert<TypeSyntaxNode>() });
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return new IdentifierList { IsRecursive = isRecursive, Children = children };
|
||||
}
|
||||
|
||||
private IEnumerable<IdentifierSemanticToken> GetIdentifiers()
|
||||
{
|
||||
IdentifierList identifier = this;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (identifier.IsRecursive)
|
||||
OnIdentifierGenerator?.Invoke(this, new OnIdentifierGeneratorEventArgs
|
||||
{
|
||||
yield return (IdentifierSemanticToken)identifier.Children[2].Convert<TerminatedSyntaxNode>().Token;
|
||||
identifier = identifier.Children[0].Convert<IdentifierList>();
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return (IdentifierSemanticToken)identifier.Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
//用逗号分隔输出的expression
|
||||
using var enumerator = Identifiers.Reverse().GetEnumerator();
|
||||
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
builder.AddString(" " + enumerator.Current.IdentifierName);
|
||||
IdentifierToken = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
IdentifierList = Children[2].Convert<IdentifierList>()
|
||||
});
|
||||
}
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
builder.AddString(", " + enumerator.Current.IdentifierName);
|
||||
}
|
||||
OnTypeGenerator = null;
|
||||
OnIdentifierGenerator = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,54 +1,46 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnParameterGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required ExpressionList Parameters { get; init; }
|
||||
}
|
||||
|
||||
public class IdentifierVarPart : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.IdVarPart;
|
||||
|
||||
/// <summary>
|
||||
/// 是否声明了索引部分
|
||||
/// </summary>
|
||||
public bool Exist { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// 索引中的位置声明
|
||||
/// </summary>
|
||||
public IEnumerable<Expression> Positions => GetPositions();
|
||||
|
||||
private IEnumerable<Expression> GetPositions()
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
if (!Exist)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (Expression expression in Children[1].Convert<ExpressionList>().Expressions)
|
||||
{
|
||||
yield return expression;
|
||||
}
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public event EventHandler<OnParameterGeneratorEventArgs>? OnParameterGenerator;
|
||||
|
||||
public static IdentifierVarPart Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
bool exist;
|
||||
|
||||
if (children.Count == 0)
|
||||
{
|
||||
exist = false;
|
||||
}
|
||||
else if (children.Count == 3)
|
||||
{
|
||||
exist = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return new IdentifierVarPart { Children = children, Exist = exist };
|
||||
return new IdentifierVarPart { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 3)
|
||||
{
|
||||
OnParameterGenerator?.Invoke(this, new OnParameterGeneratorEventArgs
|
||||
{
|
||||
Parameters = Children[1].Convert<ExpressionList>()
|
||||
});
|
||||
}
|
||||
|
||||
OnParameterGenerator = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
|
@ -8,6 +9,16 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.MultiplyOperator;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static MultiplyOperator Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new MultiplyOperator { Children = children };
|
||||
|
@ -45,6 +56,5 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
|
|||
builder.AddString(" /");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -9,6 +10,8 @@ public abstract class NonTerminatedSyntaxNode : SyntaxNodeBase, IEnumerable<Synt
|
|||
|
||||
public abstract NonTerminatorType Type { get; }
|
||||
|
||||
|
||||
|
||||
public required List<SyntaxNodeBase> Children { get; init; }
|
||||
|
||||
public IEnumerator<SyntaxNodeBase> GetEnumerator()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -17,6 +18,16 @@ public class Parameter : NonTerminatedSyntaxNode
|
|||
public ValueParameter ValueParameter =>
|
||||
IsVar ? Children[0].Convert<VarParameter>().ValueParameter : Children[0].Convert<ValueParameter>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static Parameter Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
NonTerminatedSyntaxNode node = children[0].Convert<NonTerminatedSyntaxNode>();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -13,6 +14,16 @@ public class ParameterList : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public IEnumerable<Parameter> Parameters => GetParameters();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ParameterList Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
bool isRecursive;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
|
@ -8,63 +8,61 @@ public class Period : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.Period;
|
||||
|
||||
public bool IsRecursive { get; private init; }
|
||||
/// <summary>
|
||||
/// 所有定义的Period
|
||||
/// </summary>
|
||||
public List<Period> Periods { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 数组上下界列表
|
||||
/// 数组的开始下标和结束下标
|
||||
/// </summary>
|
||||
public IEnumerable<(NumberSemanticToken, NumberSemanticToken)> Ranges => GetRanges();
|
||||
|
||||
public static Period Create(List<SyntaxNodeBase> children)
|
||||
public (NumberSemanticToken, NumberSemanticToken) Range
|
||||
{
|
||||
bool isRecursive;
|
||||
|
||||
if (children.Count == 3)
|
||||
get
|
||||
{
|
||||
isRecursive = false;
|
||||
}
|
||||
else if (children.Count == 5)
|
||||
{
|
||||
isRecursive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return new Period { Children = children, IsRecursive = isRecursive };
|
||||
}
|
||||
|
||||
private (NumberSemanticToken, NumberSemanticToken) GetRange()
|
||||
{
|
||||
if (IsRecursive)
|
||||
{
|
||||
return ((NumberSemanticToken)Children[2].Convert<TerminatedSyntaxNode>().Token,
|
||||
(NumberSemanticToken)Children[4].Convert<TerminatedSyntaxNode>().Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((NumberSemanticToken)Children[0].Convert<TerminatedSyntaxNode>().Token,
|
||||
(NumberSemanticToken)Children[2].Convert<TerminatedSyntaxNode>().Token);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<(NumberSemanticToken, NumberSemanticToken)> GetRanges()
|
||||
{
|
||||
Period period = this;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (period.IsRecursive)
|
||||
if (Children.Count == 3)
|
||||
{
|
||||
yield return period.GetRange();
|
||||
period = period.Children[0].Convert<Period>();
|
||||
return (Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<NumberSemanticToken>(),
|
||||
Children[2].Convert<TerminatedSyntaxNode>().Token.Convert<NumberSemanticToken>());
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return period.GetRange();
|
||||
break;
|
||||
return (Children[2].Convert<TerminatedSyntaxNode>().Token.Convert<NumberSemanticToken>(),
|
||||
Children[4].Convert<TerminatedSyntaxNode>().Token.Convert<NumberSemanticToken>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static Period Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
Period result = new() { Children = children };
|
||||
|
||||
if (children.Count == 3)
|
||||
{
|
||||
result.Periods.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Period child = children[0].Convert<Period>();
|
||||
|
||||
foreach (Period period in child.Periods)
|
||||
{
|
||||
result.Periods.Add(period);
|
||||
}
|
||||
|
||||
result.Periods.Add(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
|
@ -13,6 +14,16 @@ public class ProcedureCall : NonTerminatedSyntaxNode
|
|||
|
||||
public IEnumerable<Expression> Arguments => GetArguments();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ProcedureCall Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ProcedureCall { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -27,6 +28,16 @@ public class ProgramBody : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public CompoundStatement CompoundStatement => Children[3].Convert<CompoundStatement>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ProgramBody Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ProgramBody { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -13,28 +14,18 @@ public class ProgramHead : NonTerminatedSyntaxNode
|
|||
public IdentifierSemanticToken ProgramName
|
||||
=> (IdentifierSemanticToken)Children[1].Convert<TerminatedSyntaxNode>().Token;
|
||||
|
||||
/// <summary>
|
||||
/// 暂时意义不明的标识符列表
|
||||
/// https://wiki.freepascal.org/Program_Structure/zh_CN
|
||||
/// TODO: 查阅资料
|
||||
/// </summary>
|
||||
public IEnumerable<IdentifierSemanticToken> FileList => GetFileList();
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ProgramHead Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ProgramHead { Children = children };
|
||||
}
|
||||
|
||||
private IEnumerable<IdentifierSemanticToken> GetFileList()
|
||||
{
|
||||
if (Children.Count == 2)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (IdentifierSemanticToken token in Children[3].Convert<IdentifierList>().Identifiers)
|
||||
{
|
||||
yield return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -17,6 +18,16 @@ public class ProgramStruct : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public ProgramBody Body => Children[2].Convert<ProgramBody>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ProgramStruct Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ProgramStruct { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
|
@ -8,6 +9,16 @@ public class RelationOperator : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.RelationOperator;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static RelationOperator Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new RelationOperator { Children = children };
|
||||
|
@ -15,8 +26,8 @@ public class RelationOperator : NonTerminatedSyntaxNode
|
|||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
var operatorType = Children[0].Convert<TerminatedSyntaxNode>().Token.
|
||||
Convert<OperatorSemanticToken>().OperatorType;
|
||||
var operatorType = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<OperatorSemanticToken>()
|
||||
.OperatorType;
|
||||
switch (operatorType)
|
||||
{
|
||||
case OperatorType.Equal:
|
||||
|
|
|
@ -1,17 +1,97 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnTermGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Term Term { get; init; }
|
||||
}
|
||||
|
||||
public class OnAddGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required SimpleExpression Left { get; init; }
|
||||
|
||||
public required AddOperator Operator { get; init; }
|
||||
|
||||
public required Term Right { get; init; }
|
||||
}
|
||||
|
||||
public class SimpleExpression : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.SimpleExpression;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnTermGeneratorEventArgs>? OnTermGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 加法产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnAddGeneratorEventArgs>? OnAddGenerator;
|
||||
|
||||
private PascalType? _simpleExpressionType;
|
||||
|
||||
public PascalType SimpleExpressionType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_simpleExpressionType is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _simpleExpressionType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_simpleExpressionType = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static SimpleExpression Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new SimpleExpression { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnTermGenerator?.Invoke(this, new OnTermGeneratorEventArgs
|
||||
{
|
||||
Term = Children[0].Convert<Term>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnAddGenerator?.Invoke(this, new OnAddGeneratorEventArgs
|
||||
{
|
||||
Left = Children[0].Convert<SimpleExpression>(),
|
||||
Operator = Children[1].Convert<AddOperator>(),
|
||||
Right = Children[2].Convert<Term>()
|
||||
});
|
||||
}
|
||||
|
||||
OnTermGenerator = null;
|
||||
OnAddGenerator = null;
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
|
|
|
@ -1,24 +1,134 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnAssignGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Variable Variable { get; init; }
|
||||
|
||||
public required Expression Expression { get; init; }
|
||||
}
|
||||
|
||||
public class OnReturnGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken FunctionName { get; set; }
|
||||
|
||||
public required Expression Expression { get; init; }
|
||||
}
|
||||
|
||||
public class OnIfGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Expression Condition { get; init; }
|
||||
|
||||
public required Statement Sentence { get; init; }
|
||||
|
||||
public required ElsePart ElseSentence { get; init; }
|
||||
}
|
||||
|
||||
public class OnForGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required IdentifierSemanticToken Iterator { get; init; }
|
||||
|
||||
public required Expression Begin { get; init; }
|
||||
|
||||
public required Expression End { get; init; }
|
||||
|
||||
public required Statement Sentence { get; init; }
|
||||
}
|
||||
|
||||
public class Statement : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.Statement;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnAssignGeneratorEventArgs>? OnAssignGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用返回产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnReturnGeneratorEventArgs>? OnReturnGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用If产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnIfGeneratorEventArgs>? OnIfGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 使用For产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnForGeneratorEventArgs>? OnForGenerator;
|
||||
|
||||
public static Statement Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new Statement { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 2)
|
||||
{
|
||||
if (Children[0].IsTerminated)
|
||||
{
|
||||
OnReturnGenerator?.Invoke(this, new OnReturnGeneratorEventArgs
|
||||
{
|
||||
FunctionName = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
Expression = Children[2].Convert<Expression>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnAssignGenerator?.Invoke(this, new OnAssignGeneratorEventArgs
|
||||
{
|
||||
Variable = Children[0].Convert<Variable>(),
|
||||
Expression = Children[2].Convert<Expression>()
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (Children.Count == 5)
|
||||
{
|
||||
OnIfGenerator?.Invoke(this, new OnIfGeneratorEventArgs
|
||||
{
|
||||
Condition = Children[1].Convert<Expression>(),
|
||||
Sentence = Children[3].Convert<Statement>(),
|
||||
ElseSentence = Children[4].Convert<ElsePart>()
|
||||
});
|
||||
}
|
||||
else if (Children.Count == 8)
|
||||
{
|
||||
OnForGenerator?.Invoke(this, new OnForGeneratorEventArgs
|
||||
{
|
||||
Iterator = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
Begin = Children[3].Convert<Expression>(),
|
||||
End = Children[5].Convert<Expression>(),
|
||||
Sentence = Children[7].Convert<Statement>()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// statement -> procedureCall | compoundStatement
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -11,6 +12,16 @@ public class StatementList : NonTerminatedSyntaxNode
|
|||
|
||||
public IEnumerable<Statement> Statements => GetStatements();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static StatementList Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
bool isRecursive;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -17,6 +18,16 @@ public class Subprogram : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public SubprogramBody Body => Children[2].Convert<SubprogramBody>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static Subprogram Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new Subprogram { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -22,6 +23,16 @@ public class SubprogramBody : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public CompoundStatement CompoundStatement => Children[2].Convert<CompoundStatement>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static SubprogramBody Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new SubprogramBody() { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -12,6 +13,16 @@ public class SubprogramDeclarations : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
public IEnumerable<Subprogram> Subprograms => GetSubprograms();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static SubprogramDeclarations Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new SubprogramDeclarations { Children = children };
|
||||
|
|
|
@ -1,25 +1,48 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnProcedureGeneratorEventArgs : EventArgs;
|
||||
|
||||
public class OnFunctionGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required BasicType ReturnType { get; init; }
|
||||
}
|
||||
|
||||
public class SubprogramHead : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.SubprogramHead;
|
||||
|
||||
/// <summary>
|
||||
/// 过程定义还是函数定义
|
||||
/// </summary>
|
||||
public bool IsProcedure { get; private init; }
|
||||
|
||||
/// <summary>
|
||||
/// 子程序的名称
|
||||
/// </summary>
|
||||
public IdentifierSemanticToken SubprogramName =>
|
||||
(IdentifierSemanticToken)Children[1].Convert<TerminatedSyntaxNode>().Token;
|
||||
Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>();
|
||||
|
||||
/// <summary>
|
||||
/// 子程序的参数
|
||||
/// </summary>
|
||||
public IEnumerable<Parameter> Parameters => Children[2].Convert<FormalParameter>().Parameters;
|
||||
public FormalParameter Parameters => Children[2].Convert<FormalParameter>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public event EventHandler<OnProcedureGeneratorEventArgs>? OnProcedureGenerator;
|
||||
|
||||
public event EventHandler<OnFunctionGeneratorEventArgs>? OnFunctionGenerator;
|
||||
|
||||
public static SubprogramHead Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
|
@ -44,27 +67,19 @@ public class SubprogramHead : NonTerminatedSyntaxNode
|
|||
return new SubprogramHead { Children = children, IsProcedure = isProcedure };
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
private void RaiseEvent()
|
||||
{
|
||||
//可能要用到符号表
|
||||
if (IsProcedure)
|
||||
{
|
||||
builder.AddString("void ");
|
||||
OnProcedureGenerator?.Invoke(this, new OnProcedureGeneratorEventArgs());
|
||||
}
|
||||
else
|
||||
{
|
||||
//返回类型暂时未知
|
||||
builder.AddString("int ");
|
||||
OnFunctionGenerator?.Invoke(this,
|
||||
new OnFunctionGeneratorEventArgs { ReturnType = Children[4].Convert<BasicType>() });
|
||||
}
|
||||
|
||||
builder.AddString(SubprogramName.LiteralValue);
|
||||
|
||||
builder.AddString("(");
|
||||
foreach (var param in Parameters)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
builder.AddString(")");
|
||||
OnProcedureGenerator = null;
|
||||
OnFunctionGenerator = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ public abstract class SyntaxNodeBase : ICCodeGenerator
|
|||
{
|
||||
public abstract bool IsTerminated { get; }
|
||||
|
||||
public abstract void PreVisit(SyntaxNodeVisitor visitor);
|
||||
|
||||
public abstract void PostVisit(SyntaxNodeVisitor visitor);
|
||||
|
||||
public T Convert<T>() where T : SyntaxNodeBase
|
||||
{
|
||||
T? result = this as T;
|
||||
|
@ -26,7 +30,6 @@ public abstract class SyntaxNodeBase : ICCodeGenerator
|
|||
/// </summary>
|
||||
public virtual void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
@ -1,17 +1,97 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnFactorGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Factor Factor { get; init; }
|
||||
}
|
||||
|
||||
public class OnMultiplyGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Term Left { get; init; }
|
||||
|
||||
public required MultiplyOperator Operator { get; init; }
|
||||
|
||||
public required Factor Right { get; init; }
|
||||
}
|
||||
|
||||
public class Term : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.Term;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接赋值产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnFactorGeneratorEventArgs>? OnFactorGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 乘法产生式的事件
|
||||
/// </summary>
|
||||
public event EventHandler<OnMultiplyGeneratorEventArgs>? OnMultiplyGenerator;
|
||||
|
||||
private PascalType? _termType;
|
||||
|
||||
public PascalType TermType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_termType is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _termType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_termType = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static Term Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new Term { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnFactorGenerator?.Invoke(this, new OnFactorGeneratorEventArgs
|
||||
{
|
||||
Factor = Children[0].Convert<Factor>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnMultiplyGenerator?.Invoke(this, new OnMultiplyGeneratorEventArgs
|
||||
{
|
||||
Left = Children[0].Convert<Term>(),
|
||||
Operator = Children[1].Convert<MultiplyOperator>(),
|
||||
Right = Children[2].Convert<Factor>()
|
||||
});
|
||||
}
|
||||
|
||||
OnFactorGenerator = null;
|
||||
OnMultiplyGenerator = null;
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -6,6 +7,16 @@ public class TerminatedSyntaxNode : SyntaxNodeBase
|
|||
{
|
||||
public override bool IsTerminated => true;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public required SemanticToken Token { get; init; }
|
||||
|
||||
public override string ToString()
|
||||
|
|
|
@ -1,17 +1,92 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public class OnBasicTypeGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required BasicType BasicType { get; init; }
|
||||
}
|
||||
|
||||
public class OnArrayTypeGeneratorEventArgs : EventArgs
|
||||
{
|
||||
public required Period Period { get; init; }
|
||||
|
||||
public required BasicType BasicType { get; init; }
|
||||
}
|
||||
|
||||
public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
||||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.Type;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
RaiseEvent();
|
||||
}
|
||||
|
||||
public event EventHandler<OnBasicTypeGeneratorEventArgs>? OnBasicTypeGenerator;
|
||||
|
||||
public event EventHandler<OnArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
|
||||
|
||||
private PascalType? _pascalType;
|
||||
|
||||
/// <summary>
|
||||
/// Type节点制定的类型
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public PascalType PascalType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pascalType is null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return _pascalType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_pascalType = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeSyntaxNode Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new TypeSyntaxNode { Children = children };
|
||||
}
|
||||
|
||||
private void RaiseEvent()
|
||||
{
|
||||
if (Children.Count == 1)
|
||||
{
|
||||
OnBasicTypeGenerator?.Invoke(this, new OnBasicTypeGeneratorEventArgs
|
||||
{
|
||||
BasicType = Children[0].Convert<BasicType>()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
OnArrayTypeGenerator?.Invoke(this, new OnArrayTypeGeneratorEventArgs
|
||||
{
|
||||
Period = Children[2].Convert<Period>(),
|
||||
BasicType = Children[5].Convert<BasicType>()
|
||||
});
|
||||
}
|
||||
|
||||
OnBasicTypeGenerator = null;
|
||||
OnArrayTypeGenerator = null;
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
//type -> basic_type
|
||||
|
@ -22,7 +97,6 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
|
|||
//type -> array [ period ]of basic_type
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -8,23 +10,27 @@ public class ValueParameter : NonTerminatedSyntaxNode
|
|||
public override NonTerminatorType Type => NonTerminatorType.ValueParameter;
|
||||
|
||||
/// <summary>
|
||||
/// 声明的变量列表
|
||||
/// 是否为参数中的引用参数
|
||||
/// </summary>
|
||||
// public IdentifierList IdentifierList => Children[1].Convert<IdentifierList>();
|
||||
public bool IsReference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 声明的变量类型
|
||||
/// </summary>
|
||||
// public BasicType BasicType => Children[2].Convert<BasicType>();
|
||||
public IdentifierSemanticToken Token =>
|
||||
Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>();
|
||||
|
||||
public IdentifierList IdentifierList => Children[1].Convert<IdentifierList>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static ValueParameter Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new ValueParameter { Children = children };
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
//可能涉及符号表访问
|
||||
builder.AddString("valueParam ");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -6,42 +8,39 @@ public class VarDeclaration : NonTerminatedSyntaxNode
|
|||
{
|
||||
public override NonTerminatorType Type => NonTerminatorType.VarDeclaration;
|
||||
|
||||
// public bool IsRecursive { get; private init; }
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// 声明的变量
|
||||
// /// </summary>
|
||||
// public (IdentifierList, TypeSyntaxNode) Variable => GetVariable();
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
// private (IdentifierList, TypeSyntaxNode) GetVariable()
|
||||
// {
|
||||
// if (IsRecursive)
|
||||
// {
|
||||
// return (Children[2].Convert<IdentifierList>(), Children[4].Convert<TypeSyntaxNode>());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return (Children[0].Convert<IdentifierList>(), Children[2].Convert<TypeSyntaxNode>());
|
||||
// }
|
||||
// }
|
||||
public required IdentifierSemanticToken Token { get; init; }
|
||||
|
||||
public required IdentifierList IdentifierList { get; init; }
|
||||
|
||||
public static VarDeclaration Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
/*bool isRecursive;
|
||||
|
||||
if (children.Count == 2)
|
||||
{
|
||||
isRecursive = false;
|
||||
}
|
||||
else if (children.Count == 4)
|
||||
{
|
||||
isRecursive = true;
|
||||
return new VarDeclaration
|
||||
{
|
||||
Children = children,
|
||||
Token = children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
IdentifierList = children[1].Convert<IdentifierList>()
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}*/
|
||||
|
||||
return new VarDeclaration {Children = children};
|
||||
return new VarDeclaration
|
||||
{
|
||||
Children = children,
|
||||
Token = children[2].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>(),
|
||||
IdentifierList = children[3].Convert<IdentifierList>()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
|
@ -13,6 +14,16 @@ public class VarDeclarations : NonTerminatedSyntaxNode
|
|||
/// </summary>
|
||||
// public IEnumerable<(IdentifierList, TypeSyntaxNode)> Variables => EnumerateVariables();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static VarDeclarations Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new VarDeclarations { Children = children };
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
@ -9,6 +10,16 @@ public class VarParameter : NonTerminatedSyntaxNode
|
|||
|
||||
public ValueParameter ValueParameter => Children[1].Convert<ValueParameter>();
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static VarParameter Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new VarParameter { Children = children };
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -15,48 +14,18 @@ public class Variable : NonTerminatedSyntaxNode
|
|||
public IdentifierSemanticToken Identifier =>
|
||||
(IdentifierSemanticToken)Children[0].Convert<TerminatedSyntaxNode>().Token;
|
||||
|
||||
public override void PreVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PreVisit(this);
|
||||
}
|
||||
|
||||
public override void PostVisit(SyntaxNodeVisitor visitor)
|
||||
{
|
||||
visitor.PostVisit(this);
|
||||
}
|
||||
|
||||
public static Variable Create(List<SyntaxNodeBase> children)
|
||||
{
|
||||
return new Variable { Children = children };
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
//判断是否为引用变量
|
||||
builder.SymbolTable.TryGetSymbol(Identifier.IdentifierName, out var symbol);
|
||||
if (symbol is not null && symbol.Reference)
|
||||
{
|
||||
builder.AddString(" (*" + Identifier.IdentifierName + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AddString(" " + Identifier.IdentifierName);
|
||||
}
|
||||
|
||||
//处理idVarPart(数组下标部分)
|
||||
var idVarPart = Children[1].Convert<IdentifierVarPart>();
|
||||
if (idVarPart.Exist)
|
||||
{
|
||||
PascalArrayType pascalArrayType = (PascalArrayType)symbol.SymbolType;
|
||||
var positions = idVarPart.Positions;
|
||||
|
||||
foreach (var pos in positions.Reverse())
|
||||
{
|
||||
builder.AddString("[");
|
||||
pos.GenerateCCode(builder);
|
||||
//pascal下标减去左边界,从而映射到C语言的下标
|
||||
builder.AddString(" - " + System.Convert.ToString(pascalArrayType.Begin) + "]");
|
||||
|
||||
try
|
||||
{
|
||||
pascalArrayType = (PascalArrayType)pascalArrayType.ElementType;
|
||||
}
|
||||
catch (InvalidCastException e)
|
||||
{
|
||||
//do nothing
|
||||
//因为最后一层嵌套类型,必然不是PascalArrayType, 而是BasicType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ namespace Canon.Generator.Extensions;
|
|||
|
||||
public static class RootCommandExtension
|
||||
{
|
||||
public static void AddGenerateCommand(this RootCommand rootCommand)
|
||||
public static void AddGrammarCommand(this RootCommand rootCommand)
|
||||
{
|
||||
Command generateCommand = new("generate", "Generate source files.");
|
||||
Command generateCommand = new("grammar", "Generate grammar parser source files.");
|
||||
|
||||
Argument<string> filenameArgument = new(name: "filename",
|
||||
description: "determines the generated file name.",
|
||||
|
@ -37,4 +37,16 @@ public static class RootCommandExtension
|
|||
|
||||
rootCommand.AddCommand(generateCommand);
|
||||
}
|
||||
|
||||
public static void AddSyntaxVisitorCommand(this RootCommand rootCommand)
|
||||
{
|
||||
Command syntaxCommand = new("syntax", "Generate syntax visitor source code.");
|
||||
|
||||
syntaxCommand.SetHandler(async () =>
|
||||
{
|
||||
await SyntaxVisitorGenerator.SyntaxVisitorGenerator.Generate();
|
||||
});
|
||||
|
||||
rootCommand.AddCommand(syntaxCommand);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using Canon.Generator.Extensions;
|
|||
|
||||
RootCommand rootCommand = new("Canon Compiler Source Generator");
|
||||
|
||||
rootCommand.AddGenerateCommand();
|
||||
rootCommand.AddGrammarCommand();
|
||||
rootCommand.AddSyntaxVisitorCommand();
|
||||
|
||||
await rootCommand.InvokeAsync(args);
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
using System.Text;
|
||||
|
||||
namespace Canon.Generator.SyntaxVisitorGenerator;
|
||||
|
||||
public static class SyntaxVisitorGenerator
|
||||
{
|
||||
private static readonly List<string> s_nodes =
|
||||
[
|
||||
"AddOperator",
|
||||
"BasicType",
|
||||
"CompoundStatement",
|
||||
"ConstDeclaration",
|
||||
"ConstDeclarations",
|
||||
"ConstValue",
|
||||
"ElsePart",
|
||||
"Expression",
|
||||
"ExpressionList",
|
||||
"Factor",
|
||||
"FormalParameter",
|
||||
"IdentifierList",
|
||||
"IdentifierVarPart",
|
||||
"MultiplyOperator",
|
||||
"Parameter",
|
||||
"ParameterList",
|
||||
"Period",
|
||||
"ProcedureCall",
|
||||
"ProgramBody",
|
||||
"ProgramHead",
|
||||
"ProgramStruct",
|
||||
"RelationOperator",
|
||||
"SimpleExpression",
|
||||
"Statement",
|
||||
"StatementList",
|
||||
"Subprogram",
|
||||
"SubprogramBody",
|
||||
"SubprogramDeclarations",
|
||||
"SubprogramHead",
|
||||
"Term",
|
||||
"TypeSyntaxNode",
|
||||
"ValueParameter",
|
||||
"VarDeclaration",
|
||||
"VarDeclarations",
|
||||
"Variable",
|
||||
"VarParameter"
|
||||
];
|
||||
|
||||
public static async Task Generate()
|
||||
{
|
||||
FileInfo output = new(Path.Combine(Environment.CurrentDirectory, "SyntaxNodeVisitor.cs"));
|
||||
|
||||
StringBuilder builder = new();
|
||||
|
||||
builder.Append("using Canon.Core.SyntaxNodes;\n").Append('\n');
|
||||
builder.Append("namespace Canon.Core.Abstractions;\n").Append('\n');
|
||||
|
||||
builder.Append("public abstract class SyntaxNodeVisitor\n").Append("{\n");
|
||||
|
||||
foreach (string node in s_nodes)
|
||||
{
|
||||
string nodeName = node.Substring(0, 1).ToLower() + node.Substring(1);
|
||||
|
||||
builder.Append($" public virtual void PreVisit({node} {nodeName})\n")
|
||||
.Append(" {\n")
|
||||
.Append(" }\n")
|
||||
.Append('\n');
|
||||
|
||||
builder.Append($" public virtual void PostVisit({node} {nodeName})\n")
|
||||
.Append(" {\n")
|
||||
.Append(" }\n")
|
||||
.Append('\n');
|
||||
}
|
||||
|
||||
builder.Append('}');
|
||||
|
||||
await using StreamWriter writer = output.CreateText();
|
||||
await writer.WriteAsync(builder.ToString());
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
using Canon.Server.Extensions;
|
||||
using Canon.Server.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -24,6 +25,7 @@ builder.Services.AddTransient<ILexer, Lexer>();
|
|||
builder.Services.AddSingleton<IGrammarParser>(
|
||||
_ => GeneratedGrammarParser.Instance);
|
||||
builder.Services.AddSingleton<SyntaxTreePresentationService>();
|
||||
builder.Services.AddSingleton<SyntaxTreeTraveller>();
|
||||
builder.Services.AddTransient<CompilerService>();
|
||||
builder.Services.AddHostedService<DatabaseSetupService>();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Server.DataTransferObjects;
|
||||
using Canon.Server.Entities;
|
||||
|
@ -12,6 +12,7 @@ namespace Canon.Server.Services;
|
|||
public class CompilerService(
|
||||
ILexer lexer,
|
||||
IGrammarParser grammarParser,
|
||||
SyntaxTreeTraveller traveller,
|
||||
CompileDbContext dbContext,
|
||||
GridFsService gridFsService,
|
||||
SyntaxTreePresentationService syntaxTreePresentationService,
|
||||
|
@ -38,14 +39,14 @@ public class CompilerService(
|
|||
await using Stream imageStream = syntaxTreePresentationService.Present(root);
|
||||
string filename = await gridFsService.UploadStream(imageStream, "image/png");
|
||||
|
||||
CCodeBuilder builder = new();
|
||||
root.GenerateCCode(builder);
|
||||
CCodeGenerateVisitor visitor = new();
|
||||
traveller.Travel(root, visitor);
|
||||
|
||||
CompileResult result = new()
|
||||
{
|
||||
SourceCode = sourceCode.Code,
|
||||
CompileId = Guid.NewGuid().ToString(),
|
||||
CompiledCode = builder.Build(),
|
||||
CompiledCode = visitor.Builder.Build(),
|
||||
SytaxTreeImageFilename = filename,
|
||||
CompileTime = DateTime.Now
|
||||
};
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Canon.Tests.CCodeGeneratorTests;
|
||||
|
||||
public class BasicTests
|
||||
{
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
private readonly ITestOutputHelper _outputHelper;
|
||||
|
||||
public BasicTests(ITestOutputHelper outputHelper)
|
||||
{
|
||||
_outputHelper = outputHelper;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProgramStructTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program DoNothing;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> int main(){statement; return 0;}", result);
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Canon.Tests.CCodeGeneratorTests;
|
||||
|
||||
public class DeclarationsTest
|
||||
{
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
private readonly ITestOutputHelper _outputHelper;
|
||||
|
||||
public DeclarationsTest(ITestOutputHelper outputHelper)
|
||||
{
|
||||
_outputHelper = outputHelper;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VarDeclarationsTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program varTest;
|
||||
var a, b, c, d: integer; m, n: real; k: boolean;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> char a; int main(){statement; return 0; }", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstDeclarationsTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program varTest;
|
||||
const a = 1; b = 2; c = 3; d = 2.5;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> int main(){statement; return 0; }", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayDeclarationsTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program arrayTest;
|
||||
var a, b, c: array[1..6,5..8] of integer;
|
||||
d: integer;
|
||||
begin
|
||||
a[2,3] := 10086;
|
||||
d:=6;
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> int main(){statement; return 0; }", result);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Canon.Tests.CCodeGeneratorTests;
|
||||
|
||||
public class ExpressionTests
|
||||
{
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
private readonly ITestOutputHelper _outputHelper;
|
||||
|
||||
public ExpressionTests(ITestOutputHelper outputHelper)
|
||||
{
|
||||
_outputHelper = outputHelper;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExpressionTest1()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program varTest;
|
||||
var a, b, c, d: integer; m, n: real; k: boolean;
|
||||
begin
|
||||
a := 1;
|
||||
b := a + 6 * 9 + (a + 9) * 1 - (4 + a) * 5 / 1;
|
||||
m := b / 3;
|
||||
d := 9 mod 1;
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> char a; int main(){statement; return 0; }", result);
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Canon.Tests.CCodeGeneratorTests;
|
||||
|
||||
public class StatementTests
|
||||
{
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
private readonly ITestOutputHelper _outputHelper;
|
||||
|
||||
public StatementTests(ITestOutputHelper outputHelper)
|
||||
{
|
||||
_outputHelper = outputHelper;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VariableAssignTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program varAssignTest;
|
||||
var a, b: integer;
|
||||
begin
|
||||
a := 1;
|
||||
b := a;
|
||||
a := b;
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> #include <stdbool.h> " +
|
||||
"int a, b; int main(){ a = 1; b = a; a = b; return 0;}", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IfTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program main;
|
||||
var
|
||||
a,b:integer;
|
||||
begin
|
||||
if a = 5 then
|
||||
begin
|
||||
if b = 3 then
|
||||
b := b + 1
|
||||
else
|
||||
b := b + 2
|
||||
end
|
||||
else
|
||||
a := 2
|
||||
end.
|
||||
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> #include <stdbool.h> int a, b; " +
|
||||
"int main(){ a = 1; if( a == 1){ a = a + 1; } else{ b = a + 2 }; return 0;}", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForLoopTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program ForLoopTest;
|
||||
var a, b, c: integer;
|
||||
begin
|
||||
b := 1;
|
||||
for a := b * 5 + 1 to 99 do
|
||||
begin
|
||||
c := a + 1;
|
||||
b := a mod (a + c);
|
||||
b := a + 1 - 1 * 1;
|
||||
end;
|
||||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
string result = builder.Build();
|
||||
_outputHelper.WriteLine(result);
|
||||
Assert.Equal("#include <PascalCoreLib.h> #include <stdbool.h> int a, b; " +
|
||||
"int main(){ a = 1; if( a == 1){ a = a + 1; } else{ b = a + 2 }; return 0;}", result);
|
||||
}
|
||||
}
|
|
@ -1,18 +1,10 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.GeneratedParserTests;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
|
||||
namespace Canon.Tests.GrammarParserTests;
|
||||
|
||||
public class PascalGrammarTests
|
||||
{
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
|
||||
[Fact]
|
||||
public void DoNothingTest()
|
||||
{
|
||||
|
@ -22,9 +14,7 @@ public class PascalGrammarTests
|
|||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
Assert.Equal("DoNothing", root.Head.ProgramName.LiteralValue);
|
||||
Assert.Equal(15, root.Count());
|
||||
}
|
||||
|
@ -39,9 +29,8 @@ public class PascalGrammarTests
|
|||
a := 1 + 1
|
||||
end.
|
||||
""";
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
Assert.Equal("Add", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
|
@ -56,9 +45,8 @@ public class PascalGrammarTests
|
|||
writeln( str, ret );
|
||||
end.
|
||||
""";
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
Assert.Equal("exFunction", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
|
@ -73,9 +61,8 @@ public class PascalGrammarTests
|
|||
begin
|
||||
end.
|
||||
""";
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
Assert.Equal("main", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
|
@ -90,9 +77,21 @@ public class PascalGrammarTests
|
|||
end.
|
||||
""";
|
||||
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
Assert.Equal("vartest", root.Head.ProgramName.IdentifierName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayTest()
|
||||
{
|
||||
const string program = """
|
||||
program arrayTest;
|
||||
var a : array [0..10] of integer;
|
||||
begin
|
||||
a[0] := 1;
|
||||
end.
|
||||
""";
|
||||
|
||||
CompilerHelpers.Analyse(program);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,40 @@ using Canon.Tests.Utils;
|
|||
using Canon.Core.Abstractions;
|
||||
namespace Canon.Tests.LexicalParserTests
|
||||
{
|
||||
|
||||
public class NumberTests
|
||||
public class NumberTests(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
public NumberTests(ITestOutputHelper testOutputHelper)
|
||||
|
||||
[Theory]
|
||||
[InlineData("123", 123)]
|
||||
[InlineData("0", 0)]
|
||||
public void IntegerTokenTest(string input, int result)
|
||||
{
|
||||
_testOutputHelper = testOutputHelper;
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(input));
|
||||
NumberSemanticToken token = tokens.First().Convert<NumberSemanticToken>();
|
||||
|
||||
Assert.Equal(NumberType.Integer, token.NumberType);
|
||||
Assert.Equal(result, token.ParseAsInteger());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0.0", 0)]
|
||||
[InlineData("1.23", 1.23)]
|
||||
[InlineData("1e7", 1e7)]
|
||||
[InlineData("1E7", 1e7)]
|
||||
[InlineData("1.23e2", 123)]
|
||||
[InlineData("1.23E2", 123)]
|
||||
[InlineData("123e-2", 1.23)]
|
||||
[InlineData("123E-3", 0.123)]
|
||||
[InlineData("12e-7", 12e-7)]
|
||||
[InlineData(".123", 0.123)]
|
||||
public void RealTokenTest(string input, double result)
|
||||
{
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(input));
|
||||
NumberSemanticToken token = tokens.First().Convert<NumberSemanticToken>();
|
||||
|
||||
Assert.Equal(NumberType.Real, token.NumberType);
|
||||
Assert.Equal(result, token.ParseAsReal());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -50,7 +76,7 @@ namespace Canon.Tests.LexicalParserTests
|
|||
public void TestParseNumberError(string input, uint expectedLine, uint expectedCharPosition, LexemeErrorType expectedErrorType)
|
||||
{
|
||||
var ex = Assert.Throws<LexemeException>(() => _lexer.Tokenize(new StringSourceReader(input)).ToList());
|
||||
_testOutputHelper.WriteLine(ex.ToString());
|
||||
testOutputHelper.WriteLine(ex.ToString());
|
||||
Assert.Equal(expectedErrorType, ex.ErrorType);
|
||||
Assert.Equal(expectedLine, ex.Line);
|
||||
Assert.Equal(expectedCharPosition, ex.CharPosition);
|
||||
|
|
53
Canon.Tests/SemanticTests/ConstValueTests.cs
Normal file
53
Canon.Tests/SemanticTests/ConstValueTests.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.SemanticParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
|
||||
namespace Canon.Tests.SemanticTests;
|
||||
|
||||
public class ConstValueTests
|
||||
{
|
||||
private class ConstValueVisitor : SyntaxNodeVisitor
|
||||
{
|
||||
public bool Pre { get; private set; }
|
||||
|
||||
public bool Post { get; private set; }
|
||||
|
||||
public override void PreVisit(ConstValue constValue)
|
||||
{
|
||||
constValue.OnNumberGenerator += (_, _) =>
|
||||
{
|
||||
Assert.False(Pre);
|
||||
Pre = true;
|
||||
};
|
||||
}
|
||||
|
||||
public override void PostVisit(ConstValue constValue)
|
||||
{
|
||||
constValue.OnNumberGenerator += (_, _) =>
|
||||
{
|
||||
Assert.False(Post);
|
||||
Post = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RaiseEventTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
const a = 1;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
SyntaxTreeTraveller traveller = new();
|
||||
ConstValueVisitor visitor = new();
|
||||
traveller.Travel(root, visitor);
|
||||
|
||||
Assert.True(visitor.Pre);
|
||||
Assert.True(visitor.Post);
|
||||
}
|
||||
}
|
56
Canon.Tests/SemanticTests/SyntaxTreeTravellerTests.cs
Normal file
56
Canon.Tests/SemanticTests/SyntaxTreeTravellerTests.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SemanticParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
|
||||
namespace Canon.Tests.SemanticTests;
|
||||
|
||||
public class SyntaxTreeTravellerTests
|
||||
{
|
||||
private readonly ILexer _lexer = new Lexer();
|
||||
private readonly IGrammarParser _grammarParser = GeneratedGrammarParser.Instance;
|
||||
private readonly SyntaxTreeTraveller _traveller = new();
|
||||
|
||||
[Fact]
|
||||
public void TravelTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
SampleSyntaxTreeVisitor visitor = new();
|
||||
IEnumerable<SemanticToken> tokens = _lexer.Tokenize(new StringSourceReader(program));
|
||||
ProgramStruct root = _grammarParser.Analyse(tokens);
|
||||
|
||||
_traveller.Travel(root, visitor);
|
||||
|
||||
List<string> result =
|
||||
[
|
||||
"ProgramStruct",
|
||||
"ProgramHead",
|
||||
"ProgramHead",
|
||||
"ProgramBody",
|
||||
"SubprogramDeclarations",
|
||||
"SubprogramDeclarations",
|
||||
"CompoundStatement",
|
||||
"StatementList",
|
||||
"Statement",
|
||||
"Statement",
|
||||
"StatementList",
|
||||
"CompoundStatement",
|
||||
"ProgramBody",
|
||||
"ProgramStruct"
|
||||
];
|
||||
|
||||
string[] actual = visitor.ToString().Split('\n');
|
||||
|
||||
foreach ((string line, uint index) in result.WithIndex())
|
||||
{
|
||||
Assert.Equal(line, actual[(int)index]);
|
||||
}
|
||||
}
|
||||
}
|
306
Canon.Tests/SemanticTests/TypeCheckVisitorTests.cs
Normal file
306
Canon.Tests/SemanticTests/TypeCheckVisitorTests.cs
Normal file
|
@ -0,0 +1,306 @@
|
|||
using Canon.Core.SemanticParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.Utils;
|
||||
|
||||
namespace Canon.Tests.SemanticTests;
|
||||
|
||||
public class TypeCheckVisitorTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConstTypeTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
const a = 1; b = 1.23; c = 'a';
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
||||
Assert.Equal(PascalBasicType.Integer, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("b", out symbol));
|
||||
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("c", out symbol));
|
||||
Assert.Equal(PascalBasicType.Character, symbol.SymbolType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleTypeTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
var a : integer; b : char; c : boolean; d : real;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
||||
Assert.Equal(PascalBasicType.Integer, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("b", out symbol));
|
||||
Assert.Equal(PascalBasicType.Character, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("c", out symbol));
|
||||
Assert.Equal(PascalBasicType.Boolean, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("d", out symbol));
|
||||
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MulitpleTypeTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
var a, b, c, d : integer;
|
||||
e, f, g : boolean;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
IEnumerable<string> names = ["a", "b", "c", "d"];
|
||||
foreach (string name in names)
|
||||
{
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol(name, out Symbol? symbol));
|
||||
Assert.Equal(PascalBasicType.Integer, symbol.SymbolType);
|
||||
}
|
||||
|
||||
names = ["e", "f", "g"];
|
||||
foreach (string name in names)
|
||||
{
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol(name, out Symbol? symbol));
|
||||
Assert.Equal(PascalBasicType.Boolean, symbol.SymbolType);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArrayTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
var a : array [0..10] of integer;
|
||||
b : array [0..10, 0..20] of integer;
|
||||
c : array [100..200, 1..5] of real;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalArrayType(PascalBasicType.Integer, 0, 10));
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("b", out symbol));
|
||||
Assert.Equal(symbol.SymbolType,
|
||||
new PascalArrayType(new PascalArrayType(PascalBasicType.Integer, 0, 20), 0, 10));
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("c", out symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalArrayType(
|
||||
new PascalArrayType(PascalBasicType.Real, 1, 5), 100, 200));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcedureParameterTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
procedure test(a, b, c : integer);
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Integer, false)
|
||||
], PascalBasicType.Void));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcedureVarParameterTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
procedure test(var a, b, c : real);
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Real, true),
|
||||
new PascalParameterType(PascalBasicType.Real, true),
|
||||
new PascalParameterType(PascalBasicType.Real, true)
|
||||
], PascalBasicType.Void));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcedureBothParameterTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
procedure test(a, b : integer; var c, d: char);
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Character, true),
|
||||
new PascalParameterType(PascalBasicType.Character, true)
|
||||
], PascalBasicType.Void));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FunctionBothParameterTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
function test(a, b : integer; var c, d: char) : real;
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out Symbol? symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Character, true),
|
||||
new PascalParameterType(PascalBasicType.Character, true)
|
||||
], PascalBasicType.Real));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcedureAndFunctionTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
procedure test1(a : integer; var b, c : real; d: boolean);
|
||||
begin
|
||||
end;
|
||||
function test2(var a, b : boolean) : boolean;
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
TypeCheckVisitor visitor = CheckType(program);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test1", out Symbol? symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Integer, false),
|
||||
new PascalParameterType(PascalBasicType.Real, true),
|
||||
new PascalParameterType(PascalBasicType.Real, true),
|
||||
new PascalParameterType(PascalBasicType.Boolean, false)
|
||||
], PascalBasicType.Void));
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test2", out symbol));
|
||||
Assert.Equal(symbol.SymbolType, new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Boolean, true),
|
||||
new PascalParameterType(PascalBasicType.Boolean, true)
|
||||
], PascalBasicType.Boolean));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证函数中的符号表是否正确
|
||||
/// </summary>
|
||||
private class SubprogramSymbolTableTestVisitor : TypeCheckVisitor
|
||||
{
|
||||
public override void PostVisit(SubprogramBody subprogramBody)
|
||||
{
|
||||
base.PostVisit(subprogramBody);
|
||||
|
||||
Assert.True(SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
||||
Assert.Equal(PascalBasicType.Boolean, symbol.SymbolType);
|
||||
|
||||
// 递归查父符号表
|
||||
Assert.True(SymbolTable.TryGetSymbol("b", out symbol));
|
||||
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
||||
|
||||
Assert.True(SymbolTable.TryGetSymbol("c", out symbol));
|
||||
Assert.Equal(PascalBasicType.Character, symbol.SymbolType);
|
||||
|
||||
Assert.True(SymbolTable.TryGetSymbol("d", out symbol));
|
||||
Assert.Equal(PascalBasicType.Character, symbol.SymbolType);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SubprogramSymbolTableTest()
|
||||
{
|
||||
const string program = """
|
||||
program main;
|
||||
const a = 3;
|
||||
var b, c : real;
|
||||
procedure test(a : boolean);
|
||||
var c, d : char;
|
||||
begin
|
||||
end;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
SubprogramSymbolTableTestVisitor visitor = new();
|
||||
SyntaxTreeTraveller traveller = new();
|
||||
|
||||
traveller.Travel(root, visitor);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("a", out Symbol? symbol));
|
||||
Assert.Equal(PascalBasicType.Integer, symbol.SymbolType);
|
||||
Assert.True(symbol.Const);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("b", out symbol));
|
||||
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("c", out symbol));
|
||||
Assert.Equal(PascalBasicType.Real, symbol.SymbolType);
|
||||
|
||||
Assert.True(visitor.SymbolTable.TryGetSymbol("test", out symbol));
|
||||
Assert.Equal(
|
||||
new PascalFunctionType([
|
||||
new PascalParameterType(PascalBasicType.Boolean, false)
|
||||
], PascalBasicType.Void), symbol.SymbolType);
|
||||
|
||||
Assert.False(visitor.SymbolTable.TryGetSymbol("d", out symbol));
|
||||
}
|
||||
|
||||
private static TypeCheckVisitor CheckType(string program)
|
||||
{
|
||||
ProgramStruct root = CompilerHelpers.Analyse(program);
|
||||
TypeCheckVisitor visitor = new();
|
||||
SyntaxTreeTraveller traveller = new();
|
||||
|
||||
traveller.Travel(root, visitor);
|
||||
|
||||
return visitor;
|
||||
}
|
||||
}
|
18
Canon.Tests/Utils/CompilerHelpers.cs
Normal file
18
Canon.Tests/Utils/CompilerHelpers.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
|
||||
namespace Canon.Tests.Utils;
|
||||
|
||||
public static class CompilerHelpers
|
||||
{
|
||||
public static ProgramStruct Analyse(string program)
|
||||
{
|
||||
ILexer lexer = new Lexer();
|
||||
IGrammarParser grammarParser = GeneratedGrammarParser.Instance;
|
||||
|
||||
IEnumerable<SemanticToken> tokens = lexer.Tokenize(new StringSourceReader(program));
|
||||
return grammarParser.Analyse(tokens);
|
||||
}
|
||||
}
|
85
Canon.Tests/Utils/SampleSyntaxTreeVisitor.cs
Normal file
85
Canon.Tests/Utils/SampleSyntaxTreeVisitor.cs
Normal file
|
@ -0,0 +1,85 @@
|
|||
using System.Text;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
|
||||
namespace Canon.Tests.Utils;
|
||||
|
||||
public class SampleSyntaxTreeVisitor : SyntaxNodeVisitor
|
||||
{
|
||||
private readonly StringBuilder _builder = new();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _builder.ToString();
|
||||
}
|
||||
|
||||
public override void PreVisit(ProgramStruct programStruct)
|
||||
{
|
||||
_builder.Append(programStruct).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(ProgramStruct programStruct)
|
||||
{
|
||||
_builder.Append(programStruct).Append('\n');
|
||||
}
|
||||
|
||||
public override void PreVisit(ProgramHead programHead)
|
||||
{
|
||||
_builder.Append(programHead).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(ProgramHead programHead)
|
||||
{
|
||||
_builder.Append(programHead).Append('\n');
|
||||
}
|
||||
|
||||
public override void PreVisit(ProgramBody programBody)
|
||||
{
|
||||
_builder.Append(programBody).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(ProgramBody programBody)
|
||||
{
|
||||
_builder.Append(programBody).Append('\n');
|
||||
}
|
||||
|
||||
public override void PreVisit(SubprogramDeclarations subprogramDeclarations)
|
||||
{
|
||||
_builder.Append(subprogramDeclarations).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(SubprogramDeclarations subprogramDeclarations)
|
||||
{
|
||||
_builder.Append(subprogramDeclarations).Append('\n');
|
||||
}
|
||||
|
||||
public override void PreVisit(CompoundStatement compoundStatement)
|
||||
{
|
||||
_builder.Append(compoundStatement).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(CompoundStatement compoundStatement)
|
||||
{
|
||||
_builder.Append(compoundStatement).Append('\n');
|
||||
}
|
||||
|
||||
public override void PreVisit(StatementList statementList)
|
||||
{
|
||||
_builder.Append(statementList).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(StatementList statementList)
|
||||
{
|
||||
_builder.Append(statementList).Append('\n');
|
||||
}
|
||||
|
||||
public override void PreVisit(Statement statement)
|
||||
{
|
||||
_builder.Append(statement).Append('\n');
|
||||
}
|
||||
|
||||
public override void PostVisit(Statement statement)
|
||||
{
|
||||
_builder.Append(statement).Append('\n');
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user