feat-generater (#69)
Reviewed-on: PostGuard/Canon#69 Co-authored-by: Lan_G <2911328695@qq.com> Co-committed-by: Lan_G <2911328695@qq.com>
This commit is contained in:
		@@ -1,10 +1,13 @@
 | 
				
			|||||||
using Canon.Core.Abstractions;
 | 
					using System.Globalization;
 | 
				
			||||||
using Canon.Core.CodeGenerators;
 | 
					using Canon.Core.CodeGenerators;
 | 
				
			||||||
 | 
					using Canon.Core.Enums;
 | 
				
			||||||
 | 
					using Canon.Core.LexicalParser;
 | 
				
			||||||
using Canon.Core.SyntaxNodes;
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using BasicType = Canon.Core.SyntaxNodes.BasicType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Canon.Core.SemanticParser;
 | 
					namespace Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class CCodeGenerateVisitor(ICompilerLogger? logger = null) : TypeCheckVisitor(logger)
 | 
					public class CCodeGenerateVisitor : TypeCheckVisitor
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public CCodeBuilder Builder { get; } = new();
 | 
					    public CCodeBuilder Builder { get; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,4 +18,624 @@ public class CCodeGenerateVisitor(ICompilerLogger? logger = null) : TypeCheckVis
 | 
				
			|||||||
        Builder.AddString("#include <stdbool.h>\n");
 | 
					        Builder.AddString("#include <stdbool.h>\n");
 | 
				
			||||||
        Builder.AddString("#include <stdio.h>\n");
 | 
					        Builder.AddString("#include <stdio.h>\n");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string? _constValue;
 | 
				
			||||||
 | 
					    public override void PreVisit(ConstDeclaration constDeclaration)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(constDeclaration);
 | 
				
			||||||
 | 
					        (_, ConstValue constValue) = constDeclaration.ConstValue;
 | 
				
			||||||
 | 
					        constValue.OnCharacterGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _constValue = "'" + e.Token.LiteralValue + "'";
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        constValue.OnNumberGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (e.IsNegative)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _constValue = "-";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (e.Token.NumberType == NumberType.Integer)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _constValue += e.Token.ParseAsInteger();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                _constValue += e.Token.ParseAsReal();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(ConstDeclaration constDeclaration)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(constDeclaration);
 | 
				
			||||||
 | 
					        (IdentifierSemanticToken token, ConstValue constValue) = constDeclaration.ConstValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string cTypeName = TryParseBasicType(constValue.ConstType);
 | 
				
			||||||
 | 
					        Builder.AddString("const " + cTypeName + " " + token.IdentifierName + " = " + _constValue + ";\n");
 | 
				
			||||||
 | 
					        _constValue = "";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(VarDeclaration varDeclaration)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(varDeclaration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string idName = varDeclaration.Token.IdentifierName;
 | 
				
			||||||
 | 
					        var type = varDeclaration.IdentifierList.DefinitionType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (type is PascalBasicType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(idName + ";\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TryParseArrayType(type, out string _, out string periods);
 | 
				
			||||||
 | 
					            Builder.AddString(idName + periods + ";\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(IdentifierList identifierList)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(identifierList);
 | 
				
			||||||
 | 
					        identifierList.OnTypeGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            e.TypeSyntaxNode.IsProcedure = identifierList.IsProcedure;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(IdentifierList identifierList)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(identifierList);
 | 
				
			||||||
 | 
					        identifierList.OnIdentifierGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(!identifierList.IsProcedure)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                string periods = ""; //如果是数组定义,需要每个标识符后带上
 | 
				
			||||||
 | 
					                if (e.IdentifierList.DefinitionType is PascalArrayType pascalArrayType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    TryParseArrayType(pascalArrayType, out string _, out string periods0);
 | 
				
			||||||
 | 
					                    periods = periods0;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Builder.AddString(e.IdentifierToken.IdentifierName + periods + ", ");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(TypeSyntaxNode typeSyntaxNode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(typeSyntaxNode);
 | 
				
			||||||
 | 
					        typeSyntaxNode.OnBasicTypeGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            e.BasicType.IsProcedure = typeSyntaxNode.IsProcedure;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        typeSyntaxNode.OnArrayTypeGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            e.BasicType.IsProcedure = typeSyntaxNode.IsProcedure;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(BasicType basicType)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(basicType);
 | 
				
			||||||
 | 
					        if (!basicType.IsProcedure)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(TryParseBasicType(basicType.PascalType) + " ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(SubprogramHead subprogramHead)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(subprogramHead);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string subprogramName = subprogramHead.SubprogramName.IdentifierName;
 | 
				
			||||||
 | 
					        //只需特判过程,函数的返回值类型已在basicType节点上生成
 | 
				
			||||||
 | 
					        if (subprogramHead.IsProcedure)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("void ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Builder.AddString(subprogramName);
 | 
				
			||||||
 | 
					        //生成参数列表
 | 
				
			||||||
 | 
					        Builder.AddString("(");
 | 
				
			||||||
 | 
					        List<string> parametersInfo = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach (List<Symbol> children in _valueParameters)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            foreach (Symbol symbol in children.AsEnumerable().Reverse())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (symbol.SymbolType is PascalBasicType pascalType)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    string typeName = TryParseBasicType(pascalType);
 | 
				
			||||||
 | 
					                    if (symbol.Reference)
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        parametersInfo.Add(typeName + "* " + symbol.SymbolName);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        parametersInfo.Add(typeName + " " + symbol.SymbolName);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    TryParseArrayType(symbol.SymbolType, out string basicTypeName, out string periods);
 | 
				
			||||||
 | 
					                    parametersInfo.Add(string.Concat(basicTypeName, " ", symbol.SymbolName, "[]",
 | 
				
			||||||
 | 
					                        periods.Substring(periods.IndexOf(']') + 1)));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Builder.AddString(string.Join(", ", parametersInfo));
 | 
				
			||||||
 | 
					        Builder.AddString(")\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private string _subprogramName = "";
 | 
				
			||||||
 | 
					    public override void PreVisit(Subprogram subprogram)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(subprogram);
 | 
				
			||||||
 | 
					        _subprogramName = subprogram.Head.SubprogramName.IdentifierName;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(Subprogram subprogram)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(subprogram);
 | 
				
			||||||
 | 
					        if (subprogram.Head.IsProcedure)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("\n}\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //为函数生成返回语句
 | 
				
			||||||
 | 
					            Builder.AddString("return " + subprogram.Head.SubprogramName.IdentifierName + ";\n}\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(SubprogramBody subprogramBody)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(subprogramBody);
 | 
				
			||||||
 | 
					        Builder.AddString("{\n");
 | 
				
			||||||
 | 
					        //生成函数返回值变量
 | 
				
			||||||
 | 
					        SymbolTable.TryGetSymbol(_subprogramName, out var symbol);
 | 
				
			||||||
 | 
					        if (symbol is null || symbol.SymbolType is not PascalBasicType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Builder.AddString(TryParseBasicType(symbol.SymbolType.Convert<PascalType>()) + " " + _subprogramName + ";\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(ProcedureCall procedureCall)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(procedureCall);
 | 
				
			||||||
 | 
					        string procedureName = procedureCall.ProcedureId.IdentifierName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (procedureName == "read")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("scanf(\"%d\", &");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (procedureName == "write")
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("printf(\"%d\", ");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Builder.AddString(procedureName + "(");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        procedureCall.OnParameterGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            string procedureIdName = procedureCall.ProcedureId.IdentifierName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            SymbolTable.TryGetParent(out var parentTable);
 | 
				
			||||||
 | 
					            parentTable ??= SymbolTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            parentTable.TryGetSymbol(procedureIdName, out var symbol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (symbol is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            e.Parameters.ParameterTypes.AddRange(symbol.SymbolType.Convert<PascalFunctionType>().Parameters);
 | 
				
			||||||
 | 
					            e.Parameters.Expression.LastParam = true;
 | 
				
			||||||
 | 
					            e.Parameters.IsParamList = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(ProcedureCall procedureCall)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(procedureCall);
 | 
				
			||||||
 | 
					        Builder.AddString(")");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(ProgramBody programBody)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(programBody);
 | 
				
			||||||
 | 
					        //当子函数全部定义完成时,生成main函数头
 | 
				
			||||||
 | 
					        programBody.CompoundStatement.IsMain = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(CompoundStatement compoundStatement)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(compoundStatement);
 | 
				
			||||||
 | 
					        if (compoundStatement.IsMain)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("\nreturn 0;\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Builder.AddString("}\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(CompoundStatement compoundStatement)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(compoundStatement);
 | 
				
			||||||
 | 
					        if (compoundStatement.IsMain)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("int main()\n");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Builder.AddString("{\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(Statement statement)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(statement);
 | 
				
			||||||
 | 
					        statement.OnForGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            e.Begin.Iterator = e.Iterator;
 | 
				
			||||||
 | 
					            e.Begin.IsForConditionBegin = true;
 | 
				
			||||||
 | 
					            e.End.Iterator = e.Iterator;
 | 
				
			||||||
 | 
					            e.End.IsForConditionEnd = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        statement.OnAssignGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            e.Expression.IsAssign = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(Statement statement)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(statement);
 | 
				
			||||||
 | 
					        Builder.AddString(";\n");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(Variable variable)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(variable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        SymbolTable.TryGetSymbol(variable.Identifier.IdentifierName, out var symbol);
 | 
				
			||||||
 | 
					        if (symbol == null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (symbol.Reference)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("(*" + variable.Identifier.IdentifierName + ")");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(variable.Identifier.IdentifierName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (symbol.SymbolType is PascalArrayType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //解析数组类型,获取左边界列表
 | 
				
			||||||
 | 
					            List<int> leftBounds = new();
 | 
				
			||||||
 | 
					            PascalType curType = symbol.SymbolType;
 | 
				
			||||||
 | 
					            while (curType is not PascalBasicType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                leftBounds.Add(curType.Convert<PascalArrayType>().Begin);
 | 
				
			||||||
 | 
					                curType = curType.Convert<PascalArrayType>().ElementType;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //将数组维度信息向下传递
 | 
				
			||||||
 | 
					            variable.VarPart.LeftBounds.AddRange(leftBounds);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(IdentifierVarPart identifierVarPart)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(identifierVarPart);
 | 
				
			||||||
 | 
					        identifierVarPart.OnIndexGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            e.IndexParameters.IsIndex = true;
 | 
				
			||||||
 | 
					            e.IndexParameters.LeftBounds = identifierVarPart.LeftBounds;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(ExpressionList expressionList)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(expressionList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (expressionList.IsIndex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            expressionList.Expression.LeftBound = expressionList.LeftBounds.Last();
 | 
				
			||||||
 | 
					            expressionList.Expression.IsIndex = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (expressionList.IsParamList)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            expressionList.Expression.ReferenceParam = expressionList.ParameterTypes.Last().IsVar;
 | 
				
			||||||
 | 
					            expressionList.Expression.IsParam = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        expressionList.OnExpressionList += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (expressionList.IsIndex)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                e.ExpressionList.IsIndex = true;
 | 
				
			||||||
 | 
					                expressionList.LeftBounds.RemoveAt(expressionList.LeftBounds.Count - 1);
 | 
				
			||||||
 | 
					                e.ExpressionList.LeftBounds = expressionList.LeftBounds;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (expressionList.IsParamList)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                e.ExpressionList.IsParamList = true;
 | 
				
			||||||
 | 
					                for (int i = 0; i < expressionList.ParameterTypes.Count - 1; i++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    e.ExpressionList.ParameterTypes.Add(expressionList.ParameterTypes[i]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(Expression expression)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(expression);
 | 
				
			||||||
 | 
					        if (expression.IsIndex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("[");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (expression.IsForConditionBegin)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("for(" + expression.Iterator.IdentifierName + " = ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (expression.IsForConditionEnd)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(expression.Iterator.IdentifierName + " <= ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (expression.IsAssign)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(" = ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (expression.ReferenceParam)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("&");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(Expression expression)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(expression);
 | 
				
			||||||
 | 
					        if (expression.IsIndex)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            //数组下标减去当前维度的左边界
 | 
				
			||||||
 | 
					            Builder.AddString("-" + expression.LeftBound + "]");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (expression.IsForConditionEnd)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("; " + expression.Iterator.IdentifierName + "++)");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (expression is { IsParam: true, LastParam: false })
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(", ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(Factor factor)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(factor);
 | 
				
			||||||
 | 
					        factor.OnNumberGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var token = e.Token;
 | 
				
			||||||
 | 
					            string num = token.NumberType == NumberType.Integer ? token.ParseAsInteger().ToString() :
 | 
				
			||||||
 | 
					                token.ParseAsReal().ToString(CultureInfo.InvariantCulture);
 | 
				
			||||||
 | 
					            Builder.AddString(num);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        factor.OnProcedureCallGenerator += (_, _) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(")");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        factor.OnNotGenerator += (_, _) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(")");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        factor.OnUminusGenerator += (_, _) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(")");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PreVisit(Factor factor)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PreVisit(factor);
 | 
				
			||||||
 | 
					        factor.OnProcedureCallGenerator += (_, e) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(e.ProcedureName.IdentifierName + "(");
 | 
				
			||||||
 | 
					            SymbolTable.TryGetParent(out var parentTable);
 | 
				
			||||||
 | 
					            parentTable ??= SymbolTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            parentTable.TryGetSymbol(e.ProcedureName.IdentifierName, out var symbol);
 | 
				
			||||||
 | 
					            if (symbol == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            e.Parameters.ParameterTypes.AddRange(symbol.SymbolType.Convert<PascalFunctionType>().Parameters);
 | 
				
			||||||
 | 
					            e.Parameters.IsParamList = true;
 | 
				
			||||||
 | 
					            e.Parameters.Expression.LastParam = true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        factor.OnNotGenerator += (_, _) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("(!");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        factor.OnUminusGenerator += (_, _) =>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString("(-");
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(MultiplyOperator multiplyOperator)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(multiplyOperator);
 | 
				
			||||||
 | 
					        if (multiplyOperator.OperatorToken.TokenType == SemanticTokenType.Operator)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					             var operatorType = multiplyOperator.OperatorToken.Convert<OperatorSemanticToken>().OperatorType;
 | 
				
			||||||
 | 
					             if (operatorType == OperatorType.Multiply)
 | 
				
			||||||
 | 
					             {
 | 
				
			||||||
 | 
					                 Builder.AddString(" * ");
 | 
				
			||||||
 | 
					             }
 | 
				
			||||||
 | 
					             else if (operatorType == OperatorType.Divide)
 | 
				
			||||||
 | 
					             {
 | 
				
			||||||
 | 
					                 //实数除法,需要将操作数强转为double
 | 
				
			||||||
 | 
					                 Builder.AddString(" /(double)");
 | 
				
			||||||
 | 
					             }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var keywordType = multiplyOperator.OperatorToken.Convert<KeywordSemanticToken>().KeywordType;
 | 
				
			||||||
 | 
					            switch (keywordType)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                case KeywordType.And:
 | 
				
			||||||
 | 
					                    Builder.AddString(" && ");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case KeywordType.Mod:
 | 
				
			||||||
 | 
					                    Builder.AddString(" % ");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    Builder.AddString(" / ");
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(AddOperator addOperator)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(addOperator);
 | 
				
			||||||
 | 
					        var token = addOperator.OperatorToken;
 | 
				
			||||||
 | 
					        if (token.TokenType == SemanticTokenType.Operator)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var operatorType = token.Convert<OperatorSemanticToken>().OperatorType;
 | 
				
			||||||
 | 
					            if (operatorType == OperatorType.Plus)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Builder.AddString(" + ");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if (operatorType == OperatorType.Minus)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Builder.AddString(" - ");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Builder.AddString(" || ");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(RelationOperator relationOperator)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(relationOperator);
 | 
				
			||||||
 | 
					        var operatorType = relationOperator.OperatorToken.Convert<OperatorSemanticToken>().OperatorType;
 | 
				
			||||||
 | 
					        switch (operatorType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case OperatorType.Equal:
 | 
				
			||||||
 | 
					                Builder.AddString(" == ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case OperatorType.Greater:
 | 
				
			||||||
 | 
					                Builder.AddString(" > ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case OperatorType.Less:
 | 
				
			||||||
 | 
					                Builder.AddString(" < ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case OperatorType.GreaterEqual:
 | 
				
			||||||
 | 
					                Builder.AddString(" >= ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case OperatorType.LessEqual:
 | 
				
			||||||
 | 
					                Builder.AddString(" <= ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case OperatorType.NotEqual:
 | 
				
			||||||
 | 
					                Builder.AddString(" != ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override void PostVisit(TerminatedSyntaxNode terminatedSyntaxNode)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        base.PostVisit(terminatedSyntaxNode);
 | 
				
			||||||
 | 
					        string literalValue = terminatedSyntaxNode.Token.LiteralValue;
 | 
				
			||||||
 | 
					        switch (literalValue)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            case "if":
 | 
				
			||||||
 | 
					                Builder.AddString("if(");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case "then":
 | 
				
			||||||
 | 
					                Builder.AddString(")\n");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case "else":
 | 
				
			||||||
 | 
					                Builder.AddString("else\n");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case "to":
 | 
				
			||||||
 | 
					                Builder.AddString("; ");
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 尝试将pascalBasicType解析成C语言的基本类型
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <returns>C语言形式的基本类型名</returns>
 | 
				
			||||||
 | 
					    /// <exception cref="InvalidOperationException"></exception>
 | 
				
			||||||
 | 
					    private string TryParseBasicType(PascalType pascalType)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (pascalType is PascalBasicType basicType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (basicType == PascalBasicType.Integer)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return "int";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (basicType == PascalBasicType.Real)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return "double";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (basicType == PascalBasicType.Character)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return "char";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (basicType == PascalBasicType.Boolean)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return "bool";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (basicType == PascalBasicType.Void)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return "void";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        throw new InvalidOperationException("Not a basic type");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 尝试解析Pascal数组类型
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="pascalType"></param>
 | 
				
			||||||
 | 
					    /// <param name="basicTypeName">数组实际存储的元素类型</param>
 | 
				
			||||||
 | 
					    /// <param name="periods">数组下标定义</param>
 | 
				
			||||||
 | 
					    private void TryParseArrayType(PascalType pascalType, out string basicTypeName, out string periods)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        periods = "";
 | 
				
			||||||
 | 
					        PascalType curType = pascalType;
 | 
				
			||||||
 | 
					        //依次处理数组每一维
 | 
				
			||||||
 | 
					        while (curType is PascalArrayType pascalArrayType)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            int begin = pascalArrayType.Begin;
 | 
				
			||||||
 | 
					            int end = pascalArrayType.End;
 | 
				
			||||||
 | 
					            //C语言数组下标从0开始,所以下标要减去begin
 | 
				
			||||||
 | 
					            periods += "[" + (end - begin + 1) + "]";
 | 
				
			||||||
 | 
					            curType = pascalArrayType.ElementType;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        basicTypeName = TryParseBasicType(curType);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,16 @@ public abstract class PascalType : IEquatable<PascalType>
 | 
				
			|||||||
        return TypeName == other.TypeName;
 | 
					        return TypeName == other.TypeName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public T Convert<T>() where T : PascalType
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (this is T result)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        throw new InvalidOperationException("Can not convert target PascalType");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override bool Equals(object? obj)
 | 
					    public override bool Equals(object? obj)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (obj is PascalType other)
 | 
					        if (obj is PascalType other)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ using Expression = Canon.Core.SyntaxNodes.Expression;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Canon.Core.SemanticParser;
 | 
					namespace Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisitor
 | 
					public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : SyntaxNodeVisitor
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public SymbolTable SymbolTable { get; private set; } = new();
 | 
					    public SymbolTable SymbolTable { get; private set; } = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -308,7 +308,7 @@ public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisito
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 多个ValueParameter下定义的参数列表
 | 
					    /// 多个ValueParameter下定义的参数列表
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    private readonly List<List<Symbol>> _valueParameters = [];
 | 
					    protected readonly List<List<Symbol>> _valueParameters = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override void PreVisit(Subprogram subprogram)
 | 
					    public override void PreVisit(Subprogram subprogram)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,32 +9,13 @@ public class AddOperator : NonTerminatedSyntaxNode
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public override NonTerminatorType Type => NonTerminatorType.AddOperator;
 | 
					    public override NonTerminatorType Type => NonTerminatorType.AddOperator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SemanticToken OperatorToken => Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static AddOperator Create(List<SyntaxNodeBase> children)
 | 
					    public static AddOperator Create(List<SyntaxNodeBase> children)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return new AddOperator { Children = children };
 | 
					        return new AddOperator { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
					 | 
				
			||||||
        if (token.TokenType == SemanticTokenType.Operator)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var operatorType = token.Convert<OperatorSemanticToken>().OperatorType;
 | 
					 | 
				
			||||||
            if (operatorType == OperatorType.Plus)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(" +");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (operatorType == OperatorType.Minus)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(" -");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" ||");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
					    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        visitor.PreVisit(this);
 | 
					        visitor.PreVisit(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ public class BasicType : NonTerminatedSyntaxNode
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public override NonTerminatorType Type => NonTerminatorType.BasicType;
 | 
					    public override NonTerminatorType Type => NonTerminatorType.BasicType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool IsProcedure;
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// BasicType代表的Pascal类型
 | 
					    /// BasicType代表的Pascal类型
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,11 @@ public class CompoundStatement : NonTerminatedSyntaxNode
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public override NonTerminatorType Type => NonTerminatorType.CompoundStatement;
 | 
					    public override NonTerminatorType Type => NonTerminatorType.CompoundStatement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否为主函数部分
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool IsMain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
					    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        visitor.PreVisit(this);
 | 
					        visitor.PreVisit(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -126,24 +126,4 @@ public class ConstValue : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new ConstValue { Children = children };
 | 
					        return new ConstValue { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        //获取常量值
 | 
					 | 
				
			||||||
        var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
					 | 
				
			||||||
        //constValue -> 'letter'
 | 
					 | 
				
			||||||
        if (token.TokenType == SemanticTokenType.Character)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" '" + token.LiteralValue + "'");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" ");
 | 
					 | 
				
			||||||
            // constValue -> +num | -num | num
 | 
					 | 
				
			||||||
            foreach (var c in Children)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(c.Convert<TerminatedSyntaxNode>().Token.LiteralValue);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,14 +22,4 @@ public class ElsePart : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new ElsePart { Children = children };
 | 
					        return new ElsePart { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (Children.Count > 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" else{");
 | 
					 | 
				
			||||||
            Children[1].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString(" }");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
using Canon.Core.Abstractions;
 | 
					using Canon.Core.Abstractions;
 | 
				
			||||||
using Canon.Core.CodeGenerators;
 | 
					using Canon.Core.CodeGenerators;
 | 
				
			||||||
using Canon.Core.Enums;
 | 
					using Canon.Core.Enums;
 | 
				
			||||||
 | 
					using Canon.Core.LexicalParser;
 | 
				
			||||||
using Canon.Core.SemanticParser;
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Canon.Core.SyntaxNodes;
 | 
					namespace Canon.Core.SyntaxNodes;
 | 
				
			||||||
@@ -35,6 +36,43 @@ public class Expression : NonTerminatedSyntaxNode
 | 
				
			|||||||
        RaiseEvent();
 | 
					        RaiseEvent();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool IsParam;    //是否为传参
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool ReferenceParam; //是否为引用传参
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public bool LastParam;  //是否为传参列表里最后一个参数
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否为数组下标
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool IsIndex { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 当前表达式对应的数组下标维度的左边界
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public int LeftBound;
 | 
				
			||||||
 | 
					    public bool IsForConditionBegin { get; set; }
 | 
				
			||||||
 | 
					    public bool IsForConditionEnd { get; set; }
 | 
				
			||||||
 | 
					    public bool IsAssign { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private IdentifierSemanticToken? _iterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IdentifierSemanticToken Iterator
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        get
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (_iterator is null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                throw new InvalidOperationException();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return _iterator;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        set
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _iterator = value;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 直接赋值产生式的事件
 | 
					    /// 直接赋值产生式的事件
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
@@ -91,12 +129,4 @@ public class Expression : NonTerminatedSyntaxNode
 | 
				
			|||||||
        OnSimpleExpressionGenerator = null;
 | 
					        OnSimpleExpressionGenerator = null;
 | 
				
			||||||
        OnRelationGenerator = null;
 | 
					        OnRelationGenerator = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        foreach (var child in Children)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            child.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using Canon.Core.Abstractions;
 | 
					using Canon.Core.Abstractions;
 | 
				
			||||||
using Canon.Core.Enums;
 | 
					using Canon.Core.Enums;
 | 
				
			||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Canon.Core.SyntaxNodes;
 | 
					namespace Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,6 +18,23 @@ public class ExpressionList : NonTerminatedSyntaxNode
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public List<Expression> Expressions { get; } = [];
 | 
					    public List<Expression> Expressions { get; } = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否为传参列表
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool IsParamList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public List<PascalParameterType> ParameterTypes { get; } = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否为数组下标索引
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool IsIndex { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 数组左边界列表
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public List<int> LeftBounds = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// 当前ExpressionList中的Expression定义
 | 
					    /// 当前ExpressionList中的Expression定义
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -167,57 +167,4 @@ public class Factor : NonTerminatedSyntaxNode
 | 
				
			|||||||
        OnNotGenerator = null;
 | 
					        OnNotGenerator = null;
 | 
				
			||||||
        OnUminusGenerator = null;
 | 
					        OnUminusGenerator = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (Children.Count == 1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            //factor -> num
 | 
					 | 
				
			||||||
            if (Children[0].IsTerminated)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
					 | 
				
			||||||
                if (token.TokenType == SemanticTokenType.Number)
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    builder.AddString(" " + token.LiteralValue);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            // factor -> variable
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                Children[0].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //factor -> ( expression )
 | 
					 | 
				
			||||||
        else if (Children.Count == 3)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" (");
 | 
					 | 
				
			||||||
            Children[1].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString(")");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //factor -> id ( expression )
 | 
					 | 
				
			||||||
        else if (Children.Count == 4)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" " + Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>()
 | 
					 | 
				
			||||||
                .IdentifierName);
 | 
					 | 
				
			||||||
            builder.AddString("(");
 | 
					 | 
				
			||||||
            Children[2].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString(")");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            //factor -> not factor
 | 
					 | 
				
			||||||
            builder.AddString(" (");
 | 
					 | 
				
			||||||
            if (Children[0].Convert<TerminatedSyntaxNode>().Token.TokenType == SemanticTokenType.Keyword)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString("!");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString("-");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Children[1].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString(")");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
using Canon.Core.Abstractions;
 | 
					using Canon.Core.Abstractions;
 | 
				
			||||||
using Canon.Core.Enums;
 | 
					using Canon.Core.Enums;
 | 
				
			||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Canon.Core.SyntaxNodes;
 | 
					namespace Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -17,6 +18,11 @@ public class IdentifierVarPart : NonTerminatedSyntaxNode
 | 
				
			|||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public int IndexCount { get; set; }
 | 
					    public int IndexCount { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 数组左边界列表
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public List<int> LeftBounds = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
					    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        visitor.PreVisit(this);
 | 
					        visitor.PreVisit(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public override NonTerminatorType Type => NonTerminatorType.MultiplyOperator;
 | 
					    public override NonTerminatorType Type => NonTerminatorType.MultiplyOperator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SemanticToken OperatorToken => Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
					    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        visitor.PreVisit(this);
 | 
					        visitor.PreVisit(this);
 | 
				
			||||||
@@ -23,38 +25,4 @@ public class MultiplyOperator : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new MultiplyOperator { Children = children };
 | 
					        return new MultiplyOperator { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        var token = Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
					 | 
				
			||||||
        if (token.TokenType == SemanticTokenType.Operator)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var operatorType = token.Convert<OperatorSemanticToken>().OperatorType;
 | 
					 | 
				
			||||||
            if (operatorType == OperatorType.Multiply)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(" *");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (operatorType == OperatorType.Divide)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                //实数除法,需要将操作数强转为double
 | 
					 | 
				
			||||||
                builder.AddString(" /(double)");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            var keywordType = token.Convert<KeywordSemanticToken>().KeywordType;
 | 
					 | 
				
			||||||
            if (keywordType == KeywordType.And)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(" &&");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else if (keywordType == KeywordType.Mod)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(" %");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                builder.AddString(" /");
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,17 +42,4 @@ public class ProgramBody : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new ProgramBody { Children = children };
 | 
					        return new ProgramBody { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        //全局常量,变量
 | 
					 | 
				
			||||||
        ConstDeclarations.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        VarDeclarations.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        //子函数声明
 | 
					 | 
				
			||||||
        SubprogramDeclarations.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        //main函数
 | 
					 | 
				
			||||||
        builder.AddString(" int main(){");
 | 
					 | 
				
			||||||
        CompoundStatement.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        builder.AddString(" return 0;}");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,10 +32,4 @@ public class ProgramStruct : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new ProgramStruct { Children = children };
 | 
					        return new ProgramStruct { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        builder.AddString("#include <stdbool.h>");
 | 
					 | 
				
			||||||
        Body.GenerateCCode(builder);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,8 @@ public class RelationOperator : NonTerminatedSyntaxNode
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    public override NonTerminatorType Type => NonTerminatorType.RelationOperator;
 | 
					    public override NonTerminatorType Type => NonTerminatorType.RelationOperator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SemanticToken OperatorToken => Children[0].Convert<TerminatedSyntaxNode>().Token;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
					    public override void PreVisit(SyntaxNodeVisitor visitor)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        visitor.PreVisit(this);
 | 
					        visitor.PreVisit(this);
 | 
				
			||||||
@@ -23,31 +25,4 @@ public class RelationOperator : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new RelationOperator { Children = children };
 | 
					        return new RelationOperator { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        var operatorType = Children[0].Convert<TerminatedSyntaxNode>().Token.Convert<OperatorSemanticToken>()
 | 
					 | 
				
			||||||
            .OperatorType;
 | 
					 | 
				
			||||||
        switch (operatorType)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            case OperatorType.Equal:
 | 
					 | 
				
			||||||
                builder.AddString(" ==");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case OperatorType.Greater:
 | 
					 | 
				
			||||||
                builder.AddString(" >");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case OperatorType.Less:
 | 
					 | 
				
			||||||
                builder.AddString(" <");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case OperatorType.GreaterEqual:
 | 
					 | 
				
			||||||
                builder.AddString(" >=");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case OperatorType.LessEqual:
 | 
					 | 
				
			||||||
                builder.AddString(" <=");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            case OperatorType.NotEqual:
 | 
					 | 
				
			||||||
                builder.AddString(" !=");
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,12 +91,4 @@ public class SimpleExpression : NonTerminatedSyntaxNode
 | 
				
			|||||||
        OnTermGenerator = null;
 | 
					        OnTermGenerator = null;
 | 
				
			||||||
        OnAddGenerator = null;
 | 
					        OnAddGenerator = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        foreach (var child in Children)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            child.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -121,48 +121,4 @@ public class Statement : NonTerminatedSyntaxNode
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        if (Children.Count == 0)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // statement -> procedureCall | compoundStatement
 | 
					 | 
				
			||||||
        if (Children.Count == 1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Children[0].GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //statement -> variable assign expression
 | 
					 | 
				
			||||||
        else if (Children.Count == 3)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Children[0].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString(" =");
 | 
					 | 
				
			||||||
            Children[2].GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //if expression then statement else_part
 | 
					 | 
				
			||||||
        else if (Children.Count == 5)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            builder.AddString(" if(");
 | 
					 | 
				
			||||||
            Children[1].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString("){");
 | 
					 | 
				
			||||||
            Children[3].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString("; }");
 | 
					 | 
				
			||||||
            Children[4].GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //for id assign expression to expression do statement
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            string idName = Children[1].Convert<TerminatedSyntaxNode>().Token.Convert<IdentifierSemanticToken>()
 | 
					 | 
				
			||||||
                .IdentifierName;
 | 
					 | 
				
			||||||
            builder.AddString(" for(" + idName + " =");
 | 
					 | 
				
			||||||
            Children[3].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString("; " + idName + " <=");
 | 
					 | 
				
			||||||
            Children[5].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString("; " + idName + "++){");
 | 
					 | 
				
			||||||
            Children[7].GenerateCCode(builder);
 | 
					 | 
				
			||||||
            builder.AddString("; }");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,14 +32,4 @@ public class Subprogram : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new Subprogram { Children = children };
 | 
					        return new Subprogram { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        //子函数头
 | 
					 | 
				
			||||||
        Head.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        //子函数体
 | 
					 | 
				
			||||||
        builder.AddString("{");
 | 
					 | 
				
			||||||
        Body.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        builder.AddString("}");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,11 +37,4 @@ public class SubprogramBody : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new SubprogramBody() { Children = children };
 | 
					        return new SubprogramBody() { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ConstDeclarations.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        VarDeclarations.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        CompoundStatement.GenerateCCode(builder);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
using Canon.Core.Abstractions;
 | 
					using Canon.Core.Abstractions;
 | 
				
			||||||
using Canon.Core.CodeGenerators;
 | 
					 | 
				
			||||||
using Canon.Core.Enums;
 | 
					using Canon.Core.Enums;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Canon.Core.SyntaxNodes;
 | 
					namespace Canon.Core.SyntaxNodes;
 | 
				
			||||||
@@ -22,4 +21,5 @@ public class SubprogramDeclarations : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new SubprogramDeclarations { Children = children };
 | 
					        return new SubprogramDeclarations { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,12 +91,4 @@ public class Term : NonTerminatedSyntaxNode
 | 
				
			|||||||
        OnFactorGenerator = null;
 | 
					        OnFactorGenerator = null;
 | 
				
			||||||
        OnMultiplyGenerator = null;
 | 
					        OnMultiplyGenerator = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        foreach (var child in Children)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            child.GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,11 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    public event EventHandler<OnArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
 | 
					    public event EventHandler<OnArrayTypeGeneratorEventArgs>? OnArrayTypeGenerator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// 是否在过程定义中使用
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public bool IsProcedure { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private PascalType? _pascalType;
 | 
					    private PascalType? _pascalType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
@@ -86,17 +91,4 @@ public class TypeSyntaxNode : NonTerminatedSyntaxNode
 | 
				
			|||||||
        OnBasicTypeGenerator = null;
 | 
					        OnBasicTypeGenerator = null;
 | 
				
			||||||
        OnArrayTypeGenerator = null;
 | 
					        OnArrayTypeGenerator = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        //type -> basic_type
 | 
					 | 
				
			||||||
        if (Children.Count == 1)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            Children[0].GenerateCCode(builder);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        //type -> array [ period ]of basic_type
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,9 +24,4 @@ public class VarParameter : NonTerminatedSyntaxNode
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return new VarParameter { Children = children };
 | 
					        return new VarParameter { Children = children };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    public override void GenerateCCode(CCodeBuilder builder)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ValueParameter.GenerateCCode(builder);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								Canon.Tests/CodeGeneratorTests/BasicTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Canon.Tests/CodeGeneratorTests/BasicTest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using Canon.Tests.Utils;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Canon.Tests.CodeGeneratorTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BasicTest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ITestOutputHelper _output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public BasicTest(ITestOutputHelper output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _output = output;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ProgramStructTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										64
									
								
								Canon.Tests/CodeGeneratorTests/DeclarationTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Canon.Tests/CodeGeneratorTests/DeclarationTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using Canon.Tests.Utils;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Canon.Tests.CodeGeneratorTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class DeclarationTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ITestOutputHelper _output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public DeclarationTests(ITestOutputHelper output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _output = output;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ConstDeclarationTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               const a = 'a'; b = 200; c = 3.14; d = 'm';
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nconst char a = 'a';\nconst " +
 | 
				
			||||||
 | 
					                     "int b = 200;\nconst double c = 3.14;\nconst char d = 'm';\nint main()\n{\n;\n\nreturn 0;\n}\n",
 | 
				
			||||||
 | 
					            visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void VarDeclarationTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a, b, c:array[3..6, 4..999, 0..7, 8..80] of real;
 | 
				
			||||||
 | 
					                                    d, e, f:integer;
 | 
				
			||||||
 | 
					                                    g, h:array [6..8] of boolean;
 | 
				
			||||||
 | 
					                                    i, j:char;
 | 
				
			||||||
 | 
					                                    m, n:integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\ndouble c[4][996][8][73]," +
 | 
				
			||||||
 | 
					                     " b[4][996][8][73], a[4][996][8][73];\nint f, e, d;\nbool h[3], g[3];\nchar j, i;" +
 | 
				
			||||||
 | 
					                     "\nint n, m;\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										66
									
								
								Canon.Tests/CodeGeneratorTests/ExpressionTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Canon.Tests/CodeGeneratorTests/ExpressionTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using Canon.Tests.Utils;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Canon.Tests.CodeGeneratorTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ExpressionTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ITestOutputHelper _output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ExpressionTests(ITestOutputHelper output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _output = output;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ExpressionTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a, b:integer; flag, tag:boolean;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               a := 1;
 | 
				
			||||||
 | 
					                               b := a + b * 1 / 1 - 1 div 1 - - 2;
 | 
				
			||||||
 | 
					                               tag := flag or tag;
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint b, a;\n" +
 | 
				
			||||||
 | 
					                     "bool tag, flag;\nint main()\n{\na = 1;\nb = a + b * 1 /(double)1 - 1 / 1 - (-2);" +
 | 
				
			||||||
 | 
					                     "\ntag = flag || tag;\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ArrayTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a: array[9..12, 3..5, 6..20] of real; b: array[5..10] of integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                                    a[9, 4, 20] := 3.6 + b[6] - a[12, 5, 6];
 | 
				
			||||||
 | 
					                                    b[5] := 250;
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\ndouble a[4][3][15];" +
 | 
				
			||||||
 | 
					                     "\nint b[6];\nint main()\n{\na[9-9][4-3][20-6] = 3.6 + b[6-5] - a[12-9][5-3][6-6];" +
 | 
				
			||||||
 | 
					                     "\nb[5-5] = 250;\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								Canon.Tests/CodeGeneratorTests/ReadTest.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Canon.Tests/CodeGeneratorTests/ReadTest.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
				
			|||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using Canon.Tests.Utils;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Canon.Tests.CodeGeneratorTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ReadTest
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ITestOutputHelper _output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public ReadTest(ITestOutputHelper output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _output = output;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void SimpleReadTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a, b:integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               read(a);
 | 
				
			||||||
 | 
					                               write(b + 1);
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint b, a;\n" +
 | 
				
			||||||
 | 
					                     "bool tag, flag;\nint main()\n{\na = 1;\nb = a + b * 1 /(double)1 - 1 / 1 - (-2);" +
 | 
				
			||||||
 | 
					                     "\ntag = flag || tag;\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										118
									
								
								Canon.Tests/CodeGeneratorTests/StatementTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								Canon.Tests/CodeGeneratorTests/StatementTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using Canon.Tests.Utils;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Canon.Tests.CodeGeneratorTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class StatementTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ITestOutputHelper _output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public StatementTests(ITestOutputHelper output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _output = output;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void IfTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a:integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                                a := 1;
 | 
				
			||||||
 | 
					                                if a = 1 then
 | 
				
			||||||
 | 
					                                a := 1
 | 
				
			||||||
 | 
					                                else
 | 
				
			||||||
 | 
					                                begin
 | 
				
			||||||
 | 
					                                if a = 2 + a then
 | 
				
			||||||
 | 
					                                a := a
 | 
				
			||||||
 | 
					                                else a := 999;
 | 
				
			||||||
 | 
					                                end;
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint a;\nint main()\n" +
 | 
				
			||||||
 | 
					                     "{\na = 1;\nif(a == 1)\na = 1;\nelse\n{\nif(a == 2 + a)\n" +
 | 
				
			||||||
 | 
					                     "a = a;\nelse\na = 999;\n;\n;\n}\n;\n;\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ForLoopTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a, b, c:integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                                b := 5;
 | 
				
			||||||
 | 
					                                c := 6;
 | 
				
			||||||
 | 
					                                for a := 1 to 60 do
 | 
				
			||||||
 | 
					                                begin
 | 
				
			||||||
 | 
					                                    for b := a + c to 5 * a do
 | 
				
			||||||
 | 
					                                        begin
 | 
				
			||||||
 | 
					                                            c := 1;
 | 
				
			||||||
 | 
					                                        end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\n" +
 | 
				
			||||||
 | 
					                     "int c, b, a;\nint main()\n" +
 | 
				
			||||||
 | 
					                     "{\nb = 5;\nc = 6;\nfor(a = 1; a <= 60; a++){\n" +
 | 
				
			||||||
 | 
					                     "for(b = a + c; b <= 5 * a; b++)" +
 | 
				
			||||||
 | 
					                     "{\nc = 1;\n;\n}\n;\n;\n;\n}\n;\n;\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ProcedureCallTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a, b:integer; c:real;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                               function test1(var a1:integer; b1:integer; c1:real):integer;
 | 
				
			||||||
 | 
					                               var i, j, k:integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               a1:= 10086;
 | 
				
			||||||
 | 
					                               b1 := 2;
 | 
				
			||||||
 | 
					                               c1 := 63;
 | 
				
			||||||
 | 
					                               test1 := test1(i, j, k);
 | 
				
			||||||
 | 
					                               end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               test1(a, b, c);
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nint b, a;\ndouble c;" +
 | 
				
			||||||
 | 
					                     "\nint test1(int* a1, int b1, double c1)\n{" +
 | 
				
			||||||
 | 
					                     "\nint test1;\nint k, j, i;\n" +
 | 
				
			||||||
 | 
					                     "{\n(*a1) = 10086;\nb1 = 2;\nc1 = 63;\n" +
 | 
				
			||||||
 | 
					                     "test1 = test1(&i, j, k);\n;\n}\nreturn test1;\n}\n" +
 | 
				
			||||||
 | 
					                     "int main()\n{\ntest1(&a, b, c);\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								Canon.Tests/CodeGeneratorTests/SubprogramTests.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								Canon.Tests/CodeGeneratorTests/SubprogramTests.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					using Canon.Core.SemanticParser;
 | 
				
			||||||
 | 
					using Canon.Core.SyntaxNodes;
 | 
				
			||||||
 | 
					using Canon.Tests.Utils;
 | 
				
			||||||
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Canon.Tests.CodeGeneratorTests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class SubprogramTests
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly ITestOutputHelper _output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public SubprogramTests(ITestOutputHelper output)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _output = output;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void ProcedureDeclarationTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               const PI = 3.1415;
 | 
				
			||||||
 | 
					                               procedure test1;
 | 
				
			||||||
 | 
					                               var ch:char;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end;
 | 
				
			||||||
 | 
					                               procedure test2;
 | 
				
			||||||
 | 
					                               var i, j:integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nconst double pi = 3.1415;\n" +
 | 
				
			||||||
 | 
					                     "void test1()\n{\nchar ch;\n{\n;\n}\n\n}\n" +
 | 
				
			||||||
 | 
					                     "void test2()\n{\nint j, i;\n{\n;\n}\n\n}\n" +
 | 
				
			||||||
 | 
					                     "int main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [Fact]
 | 
				
			||||||
 | 
					    public void FunctionDeclarationTest()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const string program = """
 | 
				
			||||||
 | 
					                               program main;
 | 
				
			||||||
 | 
					                               var a, b: boolean;
 | 
				
			||||||
 | 
					                               function func1(var a:integer; b:integer; c:real):integer;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                                a := b + c;
 | 
				
			||||||
 | 
					                                func1 := a * 3;
 | 
				
			||||||
 | 
					                               end;
 | 
				
			||||||
 | 
					                               function func2(var a, b:boolean; c: array[0..6,3..8] of char):char;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                                a := b and not b;
 | 
				
			||||||
 | 
					                                func2 := c[5,8];
 | 
				
			||||||
 | 
					                               end;
 | 
				
			||||||
 | 
					                               begin
 | 
				
			||||||
 | 
					                               end.
 | 
				
			||||||
 | 
					                               """;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ProgramStruct root = CompilerHelpers.Analyse(program);
 | 
				
			||||||
 | 
					        SyntaxTreeTraveller traveller = new();
 | 
				
			||||||
 | 
					        CCodeGenerateVisitor visitor = new();
 | 
				
			||||||
 | 
					        traveller.Travel(root, visitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        string result = visitor.Builder.Build();
 | 
				
			||||||
 | 
					        _output.WriteLine(result);
 | 
				
			||||||
 | 
					        Assert.Equal("#include <stdbool.h>\n#include <stdio.h>\nbool b, a;" +
 | 
				
			||||||
 | 
					                     "\nint func1(int* a, int b, double c)\n{\nint func1;\n" +
 | 
				
			||||||
 | 
					                     "{\n(*a) = b + c;\nfunc1 = (*a) * 3;\n;\n}\nreturn func1;\n}\n" +
 | 
				
			||||||
 | 
					                     "char func2(bool* a, bool* b, char c[][6])\n{\nchar func2;\n" +
 | 
				
			||||||
 | 
					                     "{\n(*a) = (*b) && (!(*b));\nfunc2 = c[5-0][8-3];\n;\n}\nreturn func2;\n}" +
 | 
				
			||||||
 | 
					                     "\nint main()\n{\n;\n\nreturn 0;\n}\n", visitor.Builder.Build());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -7,7 +7,7 @@ namespace Canon.Tests.SemanticTests;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
 | 
					public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private readonly TestLogger _logger = new(testOutputHelper);
 | 
					    private readonly TestLogger<TypeCheckVisitor> _logger = new(testOutputHelper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [Fact]
 | 
					    [Fact]
 | 
				
			||||||
    public void ConstTypeTest()
 | 
					    public void ConstTypeTest()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,24 @@
 | 
				
			|||||||
using Canon.Core.Abstractions;
 | 
					using Microsoft.Extensions.Logging;
 | 
				
			||||||
using Microsoft.Extensions.Logging;
 | 
					 | 
				
			||||||
using Xunit.Abstractions;
 | 
					using Xunit.Abstractions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Canon.Tests.Utils;
 | 
					namespace Canon.Tests.Utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class TestLogger(ITestOutputHelper testOutputHelper) : ICompilerLogger
 | 
					public class TestLogger<T>(ITestOutputHelper testOutputHelper) : ILogger<T>, IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
 | 
					    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
 | 
				
			||||||
        Func<TState, Exception?, string> formatter)
 | 
					        Func<TState, Exception?, string> formatter)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        testOutputHelper.WriteLine($"{logLevel}: {formatter(state, exception)}");
 | 
					        testOutputHelper.WriteLine("{0}: {1}", logLevel, formatter(state, exception));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public string Build() => string.Empty;
 | 
					    public bool IsEnabled(LogLevel logLevel) => false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void Dispose()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public IDisposable BeginScope<TState>(TState state) where TState : notnull
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user