diff --git a/Canon.Core/Abstractions/SyntaxNodeVisitor.cs b/Canon.Core/Abstractions/SyntaxNodeVisitor.cs
new file mode 100644
index 0000000..c2c65d3
--- /dev/null
+++ b/Canon.Core/Abstractions/SyntaxNodeVisitor.cs
@@ -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)
+ {
+ }
+}
diff --git a/Canon.Core/Canon.Core.csproj b/Canon.Core/Canon.Core.csproj
index 77c284c..b7bd4a6 100644
--- a/Canon.Core/Canon.Core.csproj
+++ b/Canon.Core/Canon.Core.csproj
@@ -10,4 +10,8 @@
+
+
+
+
diff --git a/Canon.Core/LexicalParser/SemanticToken.cs b/Canon.Core/LexicalParser/SemanticToken.cs
index 958e8df..db3ba3d 100644
--- a/Canon.Core/LexicalParser/SemanticToken.cs
+++ b/Canon.Core/LexicalParser/SemanticToken.cs
@@ -160,6 +160,36 @@ public class NumberSemanticToken : SemanticToken
public required NumberType NumberType { get; init; }
+ ///
+ /// 将数值类型记号识别为整数
+ ///
+ /// 该记号表示的整数
+ /// 目标记号不是整数类型
+ public int ParseAsInteger()
+ {
+ if (NumberType != NumberType.Integer)
+ {
+ throw new InvalidOperationException("Target semantic token isn't integer");
+ }
+
+ return int.Parse(LiteralValue);
+ }
+
+ ///
+ /// 将数值类型记号识别为浮点数
+ ///
+ /// 该记号标识的浮点数
+ /// 目标记号不是浮点数类型
+ 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();
diff --git a/Canon.Core/SemanticParser/CCodeGenerateVisitor.cs b/Canon.Core/SemanticParser/CCodeGenerateVisitor.cs
new file mode 100644
index 0000000..0b68598
--- /dev/null
+++ b/Canon.Core/SemanticParser/CCodeGenerateVisitor.cs
@@ -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 \n");
+ Builder.AddString("#include \n");
+ }
+}
diff --git a/Canon.Core/SemanticParser/PascalType.cs b/Canon.Core/SemanticParser/PascalType.cs
index fe81049..9edc16b 100644
--- a/Canon.Core/SemanticParser/PascalType.cs
+++ b/Canon.Core/SemanticParser/PascalType.cs
@@ -44,4 +44,31 @@ public abstract class PascalType : IEquatable
{
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;
+ }
+ }
+
+ ///
+ /// 是否为可计算的类型
+ ///
+ /// 需要判断的Pascal类型
+ /// 是否为可计算的类型
+ public static bool IsCalculatable(PascalType pascalType)
+ {
+ return pascalType == PascalBasicType.Integer || pascalType == PascalBasicType.Real;
+ }
}
diff --git a/Canon.Core/SemanticParser/SymbolTable.cs b/Canon.Core/SemanticParser/SymbolTable.cs
index 04fbc53..cb38e95 100644
--- a/Canon.Core/SemanticParser/SymbolTable.cs
+++ b/Canon.Core/SemanticParser/SymbolTable.cs
@@ -96,6 +96,23 @@ public class SymbolTable
return false;
}
+ ///
+ /// 尝试获得父符号表
+ ///
+ /// 获得的父符号表
+ /// 是否存在父符号表
+ public bool TryGetParent([NotNullWhen(true)] out SymbolTable? parent)
+ {
+ if (_parent is null)
+ {
+ parent = null;
+ return false;
+ }
+
+ parent = _parent;
+ return true;
+ }
+
private IEnumerable GetParents()
{
SymbolTable? now = _parent;
diff --git a/Canon.Core/SemanticParser/SyntaxTreeTraveller.cs b/Canon.Core/SemanticParser/SyntaxTreeTraveller.cs
new file mode 100644
index 0000000..c55efd9
--- /dev/null
+++ b/Canon.Core/SemanticParser/SyntaxTreeTraveller.cs
@@ -0,0 +1,55 @@
+using Canon.Core.Abstractions;
+using Canon.Core.SyntaxNodes;
+
+namespace Canon.Core.SemanticParser;
+
+public class SyntaxTreeTraveller
+{
+ private readonly Stack _stack = [];
+ private readonly HashSet _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();
+
+ 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);
+ }
+ }
+ }
+}
diff --git a/Canon.Core/SemanticParser/TypeCheckVisitor.cs b/Canon.Core/SemanticParser/TypeCheckVisitor.cs
new file mode 100644
index 0000000..1d326b8
--- /dev/null
+++ b/Canon.Core/SemanticParser/TypeCheckVisitor.cs
@@ -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? 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 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
+ });
+ }
+
+ ///
+ /// 存储定义函数过程中的参数列表
+ /// 考虑到不同的ValueParameter
+ /// ValueParameter的顺序是正确的
+ /// 但ValueParameter中的顺序是相反的
+ /// 因此设置二维数组存储
+ ///
+ private List? _parameters;
+
+ ///
+ /// 多个ValueParameter下定义的参数列表
+ ///
+ private readonly List> _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 parameters = [];
+
+ // 正序遍历_valueParameter
+ // 倒序遍历其中的列表
+ foreach (List 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);
+ }
+}
diff --git a/Canon.Core/SyntaxNodes/AddOperator.cs b/Canon.Core/SyntaxNodes/AddOperator.cs
index 4b974d2..b80f4c2 100644
--- a/Canon.Core/SyntaxNodes/AddOperator.cs
+++ b/Canon.Core/SyntaxNodes/AddOperator.cs
@@ -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);
+ }
}
diff --git a/Canon.Core/SyntaxNodes/BasicType.cs b/Canon.Core/SyntaxNodes/BasicType.cs
index 77899ea..ae36bac 100644
--- a/Canon.Core/SyntaxNodes/BasicType.cs
+++ b/Canon.Core/SyntaxNodes/BasicType.cs
@@ -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 children)
+ ///
+ /// BasicType代表的Pascal类型
+ ///
+ ///
+ public PascalType PascalType
{
- return new BasicType { Children = children };
+ get
+ {
+ KeywordType keywordType = Children[0].Convert().Token
+ .Convert().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
}
}
- ///
- ///尝试获取Pascal的基本类型
- ///
- ///
- public PascalType TryGetPascalType()
+ public override void PreVisit(SyntaxNodeVisitor visitor)
{
- var keywordType = Children[0].Convert().Token
- .Convert().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 children)
+ {
+ return new BasicType { Children = children };
}
}
diff --git a/Canon.Core/SyntaxNodes/CompoundStatement.cs b/Canon.Core/SyntaxNodes/CompoundStatement.cs
index 1b77be8..e0137f4 100644
--- a/Canon.Core/SyntaxNodes/CompoundStatement.cs
+++ b/Canon.Core/SyntaxNodes/CompoundStatement.cs
@@ -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 Statements => Children[1].Convert().Statements;
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static CompoundStatement Create(List children)
{
return new CompoundStatement { Children = children };
diff --git a/Canon.Core/SyntaxNodes/ConstDeclaration.cs b/Canon.Core/SyntaxNodes/ConstDeclaration.cs
index b378348..ff72d2e 100644
--- a/Canon.Core/SyntaxNodes/ConstDeclaration.cs
+++ b/Canon.Core/SyntaxNodes/ConstDeclaration.cs
@@ -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
///
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 children)
{
bool isRecursive;
diff --git a/Canon.Core/SyntaxNodes/ConstDeclarations.cs b/Canon.Core/SyntaxNodes/ConstDeclarations.cs
index ec73030..0253813 100644
--- a/Canon.Core/SyntaxNodes/ConstDeclarations.cs
+++ b/Canon.Core/SyntaxNodes/ConstDeclarations.cs
@@ -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
///
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 children)
{
return new ConstDeclarations { Children = children };
diff --git a/Canon.Core/SyntaxNodes/ConstValue.cs b/Canon.Core/SyntaxNodes/ConstValue.cs
index 6a45034..a1ea2a9 100644
--- a/Canon.Core/SyntaxNodes/ConstValue.cs
+++ b/Canon.Core/SyntaxNodes/ConstValue.cs
@@ -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;
+///
+/// 使用数值产生式事件的事件参数
+///
+public class NumberConstValueEventArgs : EventArgs
+{
+ ///
+ /// 是否含有负号
+ ///
+ public bool IsNegative { get; init; }
+
+ ///
+ /// 数值记号
+ ///
+ public required NumberSemanticToken Token { get; init; }
+}
+
+///
+/// 使用字符产生式事件的事件参数
+///
+public class CharacterConstValueEventArgs : EventArgs
+{
+ ///
+ /// 字符记号
+ ///
+ 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;
+
+ ///
+ /// 该ConstValue代表的类型
+ ///
+ /// 尚未分析该类型
+ public PascalType ConstType
+ {
+ get
+ {
+ if (_constType is null)
+ {
+ throw new InvalidOperationException("ConstType has not been set");
+ }
+
+ return _constType;
+ }
+ set
+ {
+ _constType = value;
+ }
+ }
+
+ ///
+ /// 使用数值产生式的事件
+ ///
+ public event EventHandler? OnNumberGenerator;
+
+ ///
+ /// 使用字符产生式的事件
+ ///
+ public event EventHandler? OnCharacterGenerator;
+
+ private void RaiseGeneratorEvent()
+ {
+ if (Children.Count == 2)
+ {
+ OperatorSemanticToken operatorSemanticToken = Children[0].Convert().Token
+ .Convert();
+ NumberSemanticToken numberSemanticToken = Children[1].Convert().Token
+ .Convert();
+
+ OnNumberGenerator?.Invoke(this, new NumberConstValueEventArgs
+ {
+ Token = numberSemanticToken,
+ IsNegative = operatorSemanticToken.OperatorType == OperatorType.Minus
+ });
+
+ return;
+ }
+
+ SemanticToken token = Children[0].Convert().Token;
+
+ if (token.TokenType == SemanticTokenType.Number)
+ {
+ OnNumberGenerator?.Invoke(this,
+ new NumberConstValueEventArgs
+ {
+ Token = token.Convert()
+ });
+ }
+ else
+ {
+ OnCharacterGenerator?.Invoke(this, new CharacterConstValueEventArgs
+ {
+ Token = token.Convert()
+ });
+ }
+
+ OnNumberGenerator = null;
+ OnCharacterGenerator = null;
+ }
+
public static ConstValue Create(List children)
{
return new ConstValue { Children = children };
diff --git a/Canon.Core/SyntaxNodes/ElsePart.cs b/Canon.Core/SyntaxNodes/ElsePart.cs
index ffde0c4..d0b748f 100644
--- a/Canon.Core/SyntaxNodes/ElsePart.cs
+++ b/Canon.Core/SyntaxNodes/ElsePart.cs
@@ -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 children)
{
return new ElsePart { Children = children };
diff --git a/Canon.Core/SyntaxNodes/Expression.cs b/Canon.Core/SyntaxNodes/Expression.cs
index cd5fb1d..d334946 100644
--- a/Canon.Core/SyntaxNodes/Expression.cs
+++ b/Canon.Core/SyntaxNodes/Expression.cs
@@ -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();
+ }
+
+ ///
+ /// 直接赋值产生式的事件
+ ///
+ public event EventHandler? OnSimpleExpressionGenerator;
+
+ ///
+ /// 关系产生式的事件
+ ///
+ public event EventHandler? 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 children)
{
return new Expression { Children = children };
}
+ private void RaiseEvent()
+ {
+ if (Children.Count == 1)
+ {
+ OnSimpleExpressionGenerator?.Invoke(this, new OnSimpleExpressionGeneratorEventArgs
+ {
+ SimpleExpression = Children[0].Convert()
+ });
+ }
+ else
+ {
+ OnRelationGenerator?.Invoke(this, new OnRelationGeneratorEventArgs
+ {
+ Left = Children[0].Convert(),
+ Operator = Children[1].Convert(),
+ Right = Children[2].Convert()
+ });
+ }
+
+ OnSimpleExpressionGenerator = null;
+ OnRelationGenerator = null;
+ }
+
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var child in Children)
diff --git a/Canon.Core/SyntaxNodes/ExpressionList.cs b/Canon.Core/SyntaxNodes/ExpressionList.cs
index eed197b..59ae5d6 100644
--- a/Canon.Core/SyntaxNodes/ExpressionList.cs
+++ b/Canon.Core/SyntaxNodes/ExpressionList.cs
@@ -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; }
-
///
- /// 声明的表达式列表
+ /// 子表达式列表
///
- public IEnumerable Expressions => GetExpressions();
+ public List 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 children)
{
- bool isRecursive;
+ ExpressionList result = new() { Children = children };
if (children.Count == 1)
{
- isRecursive = false;
+ result.Expressions.Add(children[0].Convert());
}
else if (children.Count == 3)
{
- isRecursive = true;
- }
- else
- {
- throw new InvalidOperationException();
- }
-
- return new ExpressionList { Children = children, IsRecursive = isRecursive };
- }
-
- private IEnumerable GetExpressions()
- {
- ExpressionList list = this;
-
- while (true)
- {
- if (list.IsRecursive)
+ foreach (Expression expression in children[0].Convert().Expressions)
{
- yield return list.Children[2].Convert();
- list = list.Children[0].Convert();
+ result.Expressions.Add(expression);
}
- else
- {
- yield return list.Children[0].Convert();
- 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());
}
+ return result;
}
}
diff --git a/Canon.Core/SyntaxNodes/Factor.cs b/Canon.Core/SyntaxNodes/Factor.cs
index da7e977..b015f84 100644
--- a/Canon.Core/SyntaxNodes/Factor.cs
+++ b/Canon.Core/SyntaxNodes/Factor.cs
@@ -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();
+ }
+
+ ///
+ /// 使用数值产生式的事件
+ ///
+ public event EventHandler? OnNumberGenerator;
+
+ ///
+ /// 使用括号产生式的事件
+ ///
+ public event EventHandler? OnParethnesisGenerator;
+
+ ///
+ /// 使用变量产生式的事件
+ ///
+ public event EventHandler? OnVariableGenerator;
+
+ ///
+ /// 使用过程调用产生式的事件
+ ///
+ public event EventHandler? OnProcedureCallGenerator;
+
+ ///
+ /// 使用否定产生式的事件
+ ///
+ public event EventHandler? OnNotGenerator;
+
+ ///
+ /// 使用负号产生式的事件
+ ///
+ public event EventHandler? 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 children)
{
return new Factor { Children = children };
}
+ private void RaiseEvent()
+ {
+ if (Children.Count == 1)
+ {
+ //factor -> num
+ if (Children[0].IsTerminated)
+ {
+ SemanticToken token = Children[0].Convert().Token;
+ OnNumberGenerator?.Invoke(this,
+ new OnNumberGeneratorEventArgs { Token = token.Convert() });
+ }
+ // factor -> variable
+ else
+ {
+ OnVariableGenerator?.Invoke(this,
+ new OnVariableGeneratorEventArgs { Variable = Children[0].Convert() });
+ }
+ }
+ //factor -> ( expression )
+ else if (Children.Count == 3)
+ {
+ OnParethnesisGenerator?.Invoke(this,
+ new OnParethnesisGeneratorEventArgs { Expression = Children[1].Convert() });
+ }
+ //factor -> id ( expression )
+ else if (Children.Count == 4)
+ {
+ OnProcedureCallGenerator?.Invoke(this,
+ new OnProcedureCallGeneratorEventArgs
+ {
+ ProcedureName =
+ Children[0].Convert().Token.Convert(),
+ Parameters = Children[2].Convert()
+ });
+ }
+ else
+ {
+ SemanticToken token = Children[0].Convert().Token;
+ Factor factor = Children[1].Convert();
+
+ 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().Token.
- Convert().IdentifierName);
+ builder.AddString(" " + Children[0].Convert().Token.Convert()
+ .IdentifierName);
builder.AddString("(");
Children[2].GenerateCCode(builder);
builder.AddString(")");
}
else
- { //factor -> not factor
+ {
+ //factor -> not factor
builder.AddString(" (");
if (Children[0].Convert().Token.TokenType == SemanticTokenType.Keyword)
{
diff --git a/Canon.Core/SyntaxNodes/FormalParameter.cs b/Canon.Core/SyntaxNodes/FormalParameter.cs
index 59b04b6..6d02c12 100644
--- a/Canon.Core/SyntaxNodes/FormalParameter.cs
+++ b/Canon.Core/SyntaxNodes/FormalParameter.cs
@@ -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;
- ///
- /// 声明的参数列表
- ///
- public IEnumerable 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 children)
{
return new FormalParameter { Children = children };
}
-
- private IEnumerable GetParameters()
- {
- if (Children.Count == 0)
- {
- yield break;
- }
-
- foreach (Parameter parameter in Children[1].Convert().Parameters)
- {
- yield return parameter;
- }
- }
}
diff --git a/Canon.Core/SyntaxNodes/IdentifierList.cs b/Canon.Core/SyntaxNodes/IdentifierList.cs
index e67806a..86d46a2 100644
--- a/Canon.Core/SyntaxNodes/IdentifierList.cs
+++ b/Canon.Core/SyntaxNodes/IdentifierList.cs
@@ -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;
- ///
- /// 是否含有递归定义
- ///
- 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;
///
- /// 声明的标识符列表
+ /// IdentifierList中定义的类型
///
- public IEnumerable Identifiers => GetIdentifiers();
+ /// 尚未确定定义的类型
+ public PascalType DefinitionType
+ {
+ get
+ {
+ if (_definitionType is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return _definitionType;
+ }
+ set
+ {
+ _definitionType = value;
+ }
+ }
+
+ ///
+ /// 是否为参数中的引用参数
+ ///
+ public bool IsReference { get; set; }
+
+ ///
+ /// 是否在过程定义中使用
+ ///
+ public bool IsProcedure { get; set; }
+
+ public event EventHandler? OnIdentifierGenerator;
+
+ public event EventHandler? OnTypeGenerator;
public static IdentifierList Create(List 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() });
}
else
{
- throw new InvalidOperationException();
- }
-
- return new IdentifierList { IsRecursive = isRecursive, Children = children };
- }
-
- private IEnumerable GetIdentifiers()
- {
- IdentifierList identifier = this;
-
- while (true)
- {
- if (identifier.IsRecursive)
+ OnIdentifierGenerator?.Invoke(this, new OnIdentifierGeneratorEventArgs
{
- yield return (IdentifierSemanticToken)identifier.Children[2].Convert().Token;
- identifier = identifier.Children[0].Convert();
- }
- else
- {
- yield return (IdentifierSemanticToken)identifier.Children[0].Convert().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().Token.Convert(),
+ IdentifierList = Children[2].Convert()
+ });
}
- while (enumerator.MoveNext())
- {
- builder.AddString(", " + enumerator.Current.IdentifierName);
- }
+ OnTypeGenerator = null;
+ OnIdentifierGenerator = null;
}
}
diff --git a/Canon.Core/SyntaxNodes/IdentifierVarPart.cs b/Canon.Core/SyntaxNodes/IdentifierVarPart.cs
index d2619b9..cf4cc3d 100644
--- a/Canon.Core/SyntaxNodes/IdentifierVarPart.cs
+++ b/Canon.Core/SyntaxNodes/IdentifierVarPart.cs
@@ -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;
- ///
- /// 是否声明了索引部分
- ///
- public bool Exist { get; private init; }
-
- ///
- /// 索引中的位置声明
- ///
- public IEnumerable Positions => GetPositions();
-
- private IEnumerable GetPositions()
+ public override void PreVisit(SyntaxNodeVisitor visitor)
{
- if (!Exist)
- {
- yield break;
- }
-
- foreach (Expression expression in Children[1].Convert().Expressions)
- {
- yield return expression;
- }
+ visitor.PreVisit(this);
+ RaiseEvent();
}
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ RaiseEvent();
+ }
+
+ public event EventHandler? OnParameterGenerator;
+
public static IdentifierVarPart Create(List 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()
+ });
+ }
+
+ OnParameterGenerator = null;
+ }
}
diff --git a/Canon.Core/SyntaxNodes/MultiplyOperator.cs b/Canon.Core/SyntaxNodes/MultiplyOperator.cs
index dcc4b1e..e5fc726 100644
--- a/Canon.Core/SyntaxNodes/MultiplyOperator.cs
+++ b/Canon.Core/SyntaxNodes/MultiplyOperator.cs
@@ -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 children)
{
return new MultiplyOperator { Children = children };
@@ -45,6 +56,5 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
builder.AddString(" /");
}
}
-
}
}
diff --git a/Canon.Core/SyntaxNodes/NonTerminatedSyntaxNode.cs b/Canon.Core/SyntaxNodes/NonTerminatedSyntaxNode.cs
index 56422fa..be2ce28 100644
--- a/Canon.Core/SyntaxNodes/NonTerminatedSyntaxNode.cs
+++ b/Canon.Core/SyntaxNodes/NonTerminatedSyntaxNode.cs
@@ -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 Children { get; init; }
public IEnumerator GetEnumerator()
diff --git a/Canon.Core/SyntaxNodes/Parameter.cs b/Canon.Core/SyntaxNodes/Parameter.cs
index 1515ada..f4c4acc 100644
--- a/Canon.Core/SyntaxNodes/Parameter.cs
+++ b/Canon.Core/SyntaxNodes/Parameter.cs
@@ -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().ValueParameter : Children[0].Convert();
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static Parameter Create(List children)
{
NonTerminatedSyntaxNode node = children[0].Convert();
diff --git a/Canon.Core/SyntaxNodes/ParameterList.cs b/Canon.Core/SyntaxNodes/ParameterList.cs
index ae7447f..1d08df3 100644
--- a/Canon.Core/SyntaxNodes/ParameterList.cs
+++ b/Canon.Core/SyntaxNodes/ParameterList.cs
@@ -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
///
public IEnumerable 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 children)
{
bool isRecursive;
diff --git a/Canon.Core/SyntaxNodes/Period.cs b/Canon.Core/SyntaxNodes/Period.cs
index 6ddbdf2..0c40231 100644
--- a/Canon.Core/SyntaxNodes/Period.cs
+++ b/Canon.Core/SyntaxNodes/Period.cs
@@ -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; }
+ ///
+ /// 所有定义的Period
+ ///
+ public List Periods { get; } = [];
///
- /// 数组上下界列表
+ /// 数组的开始下标和结束下标
///
- public IEnumerable<(NumberSemanticToken, NumberSemanticToken)> Ranges => GetRanges();
-
- public static Period Create(List 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().Token,
- (NumberSemanticToken)Children[4].Convert().Token);
- }
- else
- {
- return ((NumberSemanticToken)Children[0].Convert().Token,
- (NumberSemanticToken)Children[2].Convert().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();
+ return (Children[0].Convert().Token.Convert(),
+ Children[2].Convert().Token.Convert());
}
else
{
- yield return period.GetRange();
- break;
+ return (Children[2].Convert().Token.Convert(),
+ Children[4].Convert().Token.Convert());
}
}
}
+
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
+ public static Period Create(List children)
+ {
+ Period result = new() { Children = children };
+
+ if (children.Count == 3)
+ {
+ result.Periods.Add(result);
+ }
+ else
+ {
+ Period child = children[0].Convert();
+
+ foreach (Period period in child.Periods)
+ {
+ result.Periods.Add(period);
+ }
+
+ result.Periods.Add(result);
+ }
+
+ return result;
+ }
}
diff --git a/Canon.Core/SyntaxNodes/ProcedureCall.cs b/Canon.Core/SyntaxNodes/ProcedureCall.cs
index 685b586..4136f42 100644
--- a/Canon.Core/SyntaxNodes/ProcedureCall.cs
+++ b/Canon.Core/SyntaxNodes/ProcedureCall.cs
@@ -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 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 children)
{
return new ProcedureCall { Children = children };
diff --git a/Canon.Core/SyntaxNodes/ProgramBody.cs b/Canon.Core/SyntaxNodes/ProgramBody.cs
index ad576e0..97d4ece 100644
--- a/Canon.Core/SyntaxNodes/ProgramBody.cs
+++ b/Canon.Core/SyntaxNodes/ProgramBody.cs
@@ -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
///
public CompoundStatement CompoundStatement => Children[3].Convert();
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static ProgramBody Create(List children)
{
return new ProgramBody { Children = children };
diff --git a/Canon.Core/SyntaxNodes/ProgramHead.cs b/Canon.Core/SyntaxNodes/ProgramHead.cs
index ffd02e4..f663b1d 100644
--- a/Canon.Core/SyntaxNodes/ProgramHead.cs
+++ b/Canon.Core/SyntaxNodes/ProgramHead.cs
@@ -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().Token;
- ///
- /// 暂时意义不明的标识符列表
- /// https://wiki.freepascal.org/Program_Structure/zh_CN
- /// TODO: 查阅资料
- ///
- public IEnumerable 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 children)
{
return new ProgramHead { Children = children };
}
-
- private IEnumerable GetFileList()
- {
- if (Children.Count == 2)
- {
- yield break;
- }
-
- foreach (IdentifierSemanticToken token in Children[3].Convert().Identifiers)
- {
- yield return token;
- }
- }
}
diff --git a/Canon.Core/SyntaxNodes/ProgramStruct.cs b/Canon.Core/SyntaxNodes/ProgramStruct.cs
index 4793e27..da98944 100644
--- a/Canon.Core/SyntaxNodes/ProgramStruct.cs
+++ b/Canon.Core/SyntaxNodes/ProgramStruct.cs
@@ -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
///
public ProgramBody Body => Children[2].Convert();
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static ProgramStruct Create(List children)
{
return new ProgramStruct { Children = children };
diff --git a/Canon.Core/SyntaxNodes/RelationOperator.cs b/Canon.Core/SyntaxNodes/RelationOperator.cs
index 382049f..067d5bc 100644
--- a/Canon.Core/SyntaxNodes/RelationOperator.cs
+++ b/Canon.Core/SyntaxNodes/RelationOperator.cs
@@ -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 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().Token.
- Convert().OperatorType;
+ var operatorType = Children[0].Convert().Token.Convert()
+ .OperatorType;
switch (operatorType)
{
case OperatorType.Equal:
diff --git a/Canon.Core/SyntaxNodes/SimpleExpression.cs b/Canon.Core/SyntaxNodes/SimpleExpression.cs
index 635c56c..72690d6 100644
--- a/Canon.Core/SyntaxNodes/SimpleExpression.cs
+++ b/Canon.Core/SyntaxNodes/SimpleExpression.cs
@@ -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();
+ }
+
+ ///
+ /// 直接赋值产生式的事件
+ ///
+ public event EventHandler? OnTermGenerator;
+
+ ///
+ /// 加法产生式的事件
+ ///
+ public event EventHandler? 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 children)
{
return new SimpleExpression { Children = children };
}
+ private void RaiseEvent()
+ {
+ if (Children.Count == 1)
+ {
+ OnTermGenerator?.Invoke(this, new OnTermGeneratorEventArgs
+ {
+ Term = Children[0].Convert()
+ });
+ }
+ else
+ {
+ OnAddGenerator?.Invoke(this, new OnAddGeneratorEventArgs
+ {
+ Left = Children[0].Convert(),
+ Operator = Children[1].Convert(),
+ Right = Children[2].Convert()
+ });
+ }
+
+ OnTermGenerator = null;
+ OnAddGenerator = null;
+ }
+
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var child in Children)
diff --git a/Canon.Core/SyntaxNodes/Statement.cs b/Canon.Core/SyntaxNodes/Statement.cs
index 4f085b6..023b4bc 100644
--- a/Canon.Core/SyntaxNodes/Statement.cs
+++ b/Canon.Core/SyntaxNodes/Statement.cs
@@ -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();
+ }
+
+ ///
+ /// 使用赋值产生式的事件
+ ///
+ public event EventHandler? OnAssignGenerator;
+
+ ///
+ /// 使用返回产生式的事件
+ ///
+ public event EventHandler? OnReturnGenerator;
+
+ ///
+ /// 使用If产生式的事件
+ ///
+ public event EventHandler? OnIfGenerator;
+
+ ///
+ /// 使用For产生式的事件
+ ///
+ public event EventHandler? OnForGenerator;
+
public static Statement Create(List 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().Token.Convert(),
+ Expression = Children[2].Convert()
+ });
+ }
+ else
+ {
+ OnAssignGenerator?.Invoke(this, new OnAssignGeneratorEventArgs
+ {
+ Variable = Children[0].Convert(),
+ Expression = Children[2].Convert()
+ });
+ }
+ }
+ else if (Children.Count == 5)
+ {
+ OnIfGenerator?.Invoke(this, new OnIfGeneratorEventArgs
+ {
+ Condition = Children[1].Convert(),
+ Sentence = Children[3].Convert(),
+ ElseSentence = Children[4].Convert()
+ });
+ }
+ else if (Children.Count == 8)
+ {
+ OnForGenerator?.Invoke(this, new OnForGeneratorEventArgs
+ {
+ Iterator = Children[1].Convert().Token.Convert(),
+ Begin = Children[3].Convert(),
+ End = Children[5].Convert(),
+ Sentence = Children[7].Convert()
+ });
+ }
+ }
+
public override void GenerateCCode(CCodeBuilder builder)
{
if (Children.Count == 0)
{
return;
}
+
// statement -> procedureCall | compoundStatement
if (Children.Count == 1)
{
diff --git a/Canon.Core/SyntaxNodes/StatementList.cs b/Canon.Core/SyntaxNodes/StatementList.cs
index ff020a6..a50323a 100644
--- a/Canon.Core/SyntaxNodes/StatementList.cs
+++ b/Canon.Core/SyntaxNodes/StatementList.cs
@@ -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 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 children)
{
bool isRecursive;
diff --git a/Canon.Core/SyntaxNodes/Subprogram.cs b/Canon.Core/SyntaxNodes/Subprogram.cs
index 12728c6..5e2d2d1 100644
--- a/Canon.Core/SyntaxNodes/Subprogram.cs
+++ b/Canon.Core/SyntaxNodes/Subprogram.cs
@@ -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
///
public SubprogramBody Body => Children[2].Convert();
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static Subprogram Create(List children)
{
return new Subprogram { Children = children };
diff --git a/Canon.Core/SyntaxNodes/SubprogramBody.cs b/Canon.Core/SyntaxNodes/SubprogramBody.cs
index 19503ae..60e5ee4 100644
--- a/Canon.Core/SyntaxNodes/SubprogramBody.cs
+++ b/Canon.Core/SyntaxNodes/SubprogramBody.cs
@@ -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
///
public CompoundStatement CompoundStatement => Children[2].Convert();
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static SubprogramBody Create(List children)
{
return new SubprogramBody() { Children = children };
diff --git a/Canon.Core/SyntaxNodes/SubprogramDeclarations.cs b/Canon.Core/SyntaxNodes/SubprogramDeclarations.cs
index 7fe6cdc..bcdd455 100644
--- a/Canon.Core/SyntaxNodes/SubprogramDeclarations.cs
+++ b/Canon.Core/SyntaxNodes/SubprogramDeclarations.cs
@@ -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
///
public IEnumerable 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 children)
{
return new SubprogramDeclarations { Children = children };
diff --git a/Canon.Core/SyntaxNodes/SubprogramHead.cs b/Canon.Core/SyntaxNodes/SubprogramHead.cs
index ad720a7..793356e 100644
--- a/Canon.Core/SyntaxNodes/SubprogramHead.cs
+++ b/Canon.Core/SyntaxNodes/SubprogramHead.cs
@@ -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;
+ ///
+ /// 过程定义还是函数定义
+ ///
public bool IsProcedure { get; private init; }
///
/// 子程序的名称
///
public IdentifierSemanticToken SubprogramName =>
- (IdentifierSemanticToken)Children[1].Convert().Token;
+ Children[1].Convert().Token.Convert();
- ///
- /// 子程序的参数
- ///
- public IEnumerable Parameters => Children[2].Convert().Parameters;
+ public FormalParameter Parameters => Children[2].Convert();
+
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ RaiseEvent();
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ RaiseEvent();
+ }
+
+ public event EventHandler? OnProcedureGenerator;
+
+ public event EventHandler? OnFunctionGenerator;
public static SubprogramHead Create(List 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() });
}
- builder.AddString(SubprogramName.LiteralValue);
-
- builder.AddString("(");
- foreach (var param in Parameters)
- {
-
- }
-
- builder.AddString(")");
+ OnProcedureGenerator = null;
+ OnFunctionGenerator = null;
}
}
diff --git a/Canon.Core/SyntaxNodes/SyntaxNodeBase.cs b/Canon.Core/SyntaxNodes/SyntaxNodeBase.cs
index 0af0507..bf589e7 100644
--- a/Canon.Core/SyntaxNodes/SyntaxNodeBase.cs
+++ b/Canon.Core/SyntaxNodes/SyntaxNodeBase.cs
@@ -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() where T : SyntaxNodeBase
{
T? result = this as T;
@@ -26,7 +30,6 @@ public abstract class SyntaxNodeBase : ICCodeGenerator
///
public virtual void GenerateCCode(CCodeBuilder builder)
{
-
}
public override string ToString()
diff --git a/Canon.Core/SyntaxNodes/Term.cs b/Canon.Core/SyntaxNodes/Term.cs
index 914c6d2..a6274b6 100644
--- a/Canon.Core/SyntaxNodes/Term.cs
+++ b/Canon.Core/SyntaxNodes/Term.cs
@@ -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();
+ }
+
+ ///
+ /// 直接赋值产生式的事件
+ ///
+ public event EventHandler? OnFactorGenerator;
+
+ ///
+ /// 乘法产生式的事件
+ ///
+ public event EventHandler? 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 children)
{
return new Term { Children = children };
}
+ private void RaiseEvent()
+ {
+ if (Children.Count == 1)
+ {
+ OnFactorGenerator?.Invoke(this, new OnFactorGeneratorEventArgs
+ {
+ Factor = Children[0].Convert()
+ });
+ }
+ else
+ {
+ OnMultiplyGenerator?.Invoke(this, new OnMultiplyGeneratorEventArgs
+ {
+ Left = Children[0].Convert(),
+ Operator = Children[1].Convert(),
+ Right = Children[2].Convert()
+ });
+ }
+
+ OnFactorGenerator = null;
+ OnMultiplyGenerator = null;
+ }
+
public override void GenerateCCode(CCodeBuilder builder)
{
foreach (var child in Children)
diff --git a/Canon.Core/SyntaxNodes/TerminatedSyntaxNode.cs b/Canon.Core/SyntaxNodes/TerminatedSyntaxNode.cs
index f996a8a..e26bb57 100644
--- a/Canon.Core/SyntaxNodes/TerminatedSyntaxNode.cs
+++ b/Canon.Core/SyntaxNodes/TerminatedSyntaxNode.cs
@@ -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()
diff --git a/Canon.Core/SyntaxNodes/TypeSyntaxNode.cs b/Canon.Core/SyntaxNodes/TypeSyntaxNode.cs
index b1fec76..e1e2c1c 100644
--- a/Canon.Core/SyntaxNodes/TypeSyntaxNode.cs
+++ b/Canon.Core/SyntaxNodes/TypeSyntaxNode.cs
@@ -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? OnBasicTypeGenerator;
+
+ public event EventHandler? OnArrayTypeGenerator;
+
+ private PascalType? _pascalType;
+
+ ///
+ /// Type节点制定的类型
+ ///
+ ///
+ public PascalType PascalType
+ {
+ get
+ {
+ if (_pascalType is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return _pascalType;
+ }
+ set
+ {
+ _pascalType = value;
+ }
+ }
+
public static TypeSyntaxNode Create(List children)
{
return new TypeSyntaxNode { Children = children };
}
+ private void RaiseEvent()
+ {
+ if (Children.Count == 1)
+ {
+ OnBasicTypeGenerator?.Invoke(this, new OnBasicTypeGeneratorEventArgs
+ {
+ BasicType = Children[0].Convert()
+ });
+ }
+ else
+ {
+ OnArrayTypeGenerator?.Invoke(this, new OnArrayTypeGeneratorEventArgs
+ {
+ Period = Children[2].Convert(),
+ BasicType = Children[5].Convert()
+ });
+ }
+
+ 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
{
-
}
}
}
diff --git a/Canon.Core/SyntaxNodes/ValueParameter.cs b/Canon.Core/SyntaxNodes/ValueParameter.cs
index 312d196..23cc84d 100644
--- a/Canon.Core/SyntaxNodes/ValueParameter.cs
+++ b/Canon.Core/SyntaxNodes/ValueParameter.cs
@@ -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;
///
- /// 声明的变量列表
+ /// 是否为参数中的引用参数
///
- // public IdentifierList IdentifierList => Children[1].Convert();
+ public bool IsReference { get; set; }
- ///
- /// 声明的变量类型
- ///
- // public BasicType BasicType => Children[2].Convert();
+ public IdentifierSemanticToken Token =>
+ Children[0].Convert().Token.Convert();
+
+ public IdentifierList IdentifierList => Children[1].Convert();
+
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
public static ValueParameter Create(List children)
{
return new ValueParameter { Children = children };
}
-
- public override void GenerateCCode(CCodeBuilder builder)
- {
- //可能涉及符号表访问
- builder.AddString("valueParam ");
- }
}
diff --git a/Canon.Core/SyntaxNodes/VarDeclaration.cs b/Canon.Core/SyntaxNodes/VarDeclaration.cs
index 6eda29a..cebc754 100644
--- a/Canon.Core/SyntaxNodes/VarDeclaration.cs
+++ b/Canon.Core/SyntaxNodes/VarDeclaration.cs
@@ -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);
+ }
- // ///
- // /// 声明的变量
- // ///
- // public (IdentifierList, TypeSyntaxNode) Variable => GetVariable();
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
- // private (IdentifierList, TypeSyntaxNode) GetVariable()
- // {
- // if (IsRecursive)
- // {
- // return (Children[2].Convert(), Children[4].Convert());
- // }
- // else
- // {
- // return (Children[0].Convert(), Children[2].Convert());
- // }
- // }
+ public required IdentifierSemanticToken Token { get; init; }
+
+ public required IdentifierList IdentifierList { get; init; }
public static VarDeclaration Create(List 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().Token.Convert(),
+ IdentifierList = children[1].Convert()
+ };
}
else
{
- throw new InvalidOperationException();
- }*/
-
- return new VarDeclaration {Children = children};
+ return new VarDeclaration
+ {
+ Children = children,
+ Token = children[2].Convert().Token.Convert(),
+ IdentifierList = children[3].Convert()
+ };
+ }
}
}
diff --git a/Canon.Core/SyntaxNodes/VarDeclarations.cs b/Canon.Core/SyntaxNodes/VarDeclarations.cs
index bf2951e..e9af74d 100644
--- a/Canon.Core/SyntaxNodes/VarDeclarations.cs
+++ b/Canon.Core/SyntaxNodes/VarDeclarations.cs
@@ -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
///
// 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 children)
{
return new VarDeclarations { Children = children };
diff --git a/Canon.Core/SyntaxNodes/VarParameter.cs b/Canon.Core/SyntaxNodes/VarParameter.cs
index 08c700e..d22872b 100644
--- a/Canon.Core/SyntaxNodes/VarParameter.cs
+++ b/Canon.Core/SyntaxNodes/VarParameter.cs
@@ -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();
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static VarParameter Create(List children)
{
return new VarParameter { Children = children };
diff --git a/Canon.Core/SyntaxNodes/Variable.cs b/Canon.Core/SyntaxNodes/Variable.cs
index 608eb11..df7d1c1 100644
--- a/Canon.Core/SyntaxNodes/Variable.cs
+++ b/Canon.Core/SyntaxNodes/Variable.cs
@@ -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().Token;
+ public override void PreVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PreVisit(this);
+ }
+
+ public override void PostVisit(SyntaxNodeVisitor visitor)
+ {
+ visitor.PostVisit(this);
+ }
+
public static Variable Create(List 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();
- 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
- }
- }
- }
- }
}
diff --git a/Canon.Generator/Extensions/RootCommandExtension.cs b/Canon.Generator/Extensions/RootCommandExtension.cs
index 3538261..a00d02f 100644
--- a/Canon.Generator/Extensions/RootCommandExtension.cs
+++ b/Canon.Generator/Extensions/RootCommandExtension.cs
@@ -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 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);
+ }
}
diff --git a/Canon.Generator/Program.cs b/Canon.Generator/Program.cs
index 3e1c7b1..19d4e61 100644
--- a/Canon.Generator/Program.cs
+++ b/Canon.Generator/Program.cs
@@ -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);
diff --git a/Canon.Generator/SyntaxVisitorGenerator/SyntaxVisitorGenerator.cs b/Canon.Generator/SyntaxVisitorGenerator/SyntaxVisitorGenerator.cs
new file mode 100644
index 0000000..2c9f1e1
--- /dev/null
+++ b/Canon.Generator/SyntaxVisitorGenerator/SyntaxVisitorGenerator.cs
@@ -0,0 +1,78 @@
+using System.Text;
+
+namespace Canon.Generator.SyntaxVisitorGenerator;
+
+public static class SyntaxVisitorGenerator
+{
+ private static readonly List 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());
+ }
+}
diff --git a/Canon.Server/Program.cs b/Canon.Server/Program.cs
index ac5cb0b..94ca0b6 100644
--- a/Canon.Server/Program.cs
+++ b/Canon.Server/Program.cs
@@ -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();
builder.Services.AddSingleton(
_ => GeneratedGrammarParser.Instance);
builder.Services.AddSingleton();
+builder.Services.AddSingleton();
builder.Services.AddTransient();
builder.Services.AddHostedService();
diff --git a/Canon.Server/Services/CompilerService.cs b/Canon.Server/Services/CompilerService.cs
index 91fb0d8..f5464d8 100644
--- a/Canon.Server/Services/CompilerService.cs
+++ b/Canon.Server/Services/CompilerService.cs
@@ -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
};
diff --git a/Canon.Tests/CCodeGeneratorTests/BasicTests.cs b/Canon.Tests/CCodeGeneratorTests/BasicTests.cs
deleted file mode 100644
index bf46dd8..0000000
--- a/Canon.Tests/CCodeGeneratorTests/BasicTests.cs
+++ /dev/null
@@ -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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include int main(){statement; return 0;}", result);
- }
-}
diff --git a/Canon.Tests/CCodeGeneratorTests/DeclarationsTests.cs b/Canon.Tests/CCodeGeneratorTests/DeclarationsTests.cs
deleted file mode 100644
index 68a9bb3..0000000
--- a/Canon.Tests/CCodeGeneratorTests/DeclarationsTests.cs
+++ /dev/null
@@ -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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include 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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include 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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include int main(){statement; return 0; }", result);
- }
-}
diff --git a/Canon.Tests/CCodeGeneratorTests/ExpressionTests.cs b/Canon.Tests/CCodeGeneratorTests/ExpressionTests.cs
deleted file mode 100644
index 833d90a..0000000
--- a/Canon.Tests/CCodeGeneratorTests/ExpressionTests.cs
+++ /dev/null
@@ -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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include char a; int main(){statement; return 0; }", result);
- }
-}
diff --git a/Canon.Tests/CCodeGeneratorTests/StatementTests.cs b/Canon.Tests/CCodeGeneratorTests/StatementTests.cs
deleted file mode 100644
index 97806f7..0000000
--- a/Canon.Tests/CCodeGeneratorTests/StatementTests.cs
+++ /dev/null
@@ -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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include #include " +
- "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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include #include 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 tokens = _lexer.Tokenize(new StringSourceReader(program));
-
- ProgramStruct root = _parser.Analyse(tokens);
- root.GenerateCCode(builder);
-
- string result = builder.Build();
- _outputHelper.WriteLine(result);
- Assert.Equal("#include #include int a, b; " +
- "int main(){ a = 1; if( a == 1){ a = a + 1; } else{ b = a + 2 }; return 0;}", result);
- }
-}
diff --git a/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs b/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
index 0cccbee..757927c 100644
--- a/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
+++ b/Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
@@ -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 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 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 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 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 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);
+ }
}
diff --git a/Canon.Tests/LexicalParserTests/NumberTests.cs b/Canon.Tests/LexicalParserTests/NumberTests.cs
index 7b815d4..4bcb53e 100644
--- a/Canon.Tests/LexicalParserTests/NumberTests.cs
+++ b/Canon.Tests/LexicalParserTests/NumberTests.cs
@@ -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 tokens = _lexer.Tokenize(new StringSourceReader(input));
+ NumberSemanticToken token = tokens.First().Convert();
+
+ 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 tokens = _lexer.Tokenize(new StringSourceReader(input));
+ NumberSemanticToken token = tokens.First().Convert();
+
+ 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(() => _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);
diff --git a/Canon.Tests/SemanticTests/ConstValueTests.cs b/Canon.Tests/SemanticTests/ConstValueTests.cs
new file mode 100644
index 0000000..bc19175
--- /dev/null
+++ b/Canon.Tests/SemanticTests/ConstValueTests.cs
@@ -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);
+ }
+}
diff --git a/Canon.Tests/SemanticTests/SyntaxTreeTravellerTests.cs b/Canon.Tests/SemanticTests/SyntaxTreeTravellerTests.cs
new file mode 100644
index 0000000..9ccd13a
--- /dev/null
+++ b/Canon.Tests/SemanticTests/SyntaxTreeTravellerTests.cs
@@ -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